精华内容
下载资源
问答
  • C++代码编写规范

    千次阅读 2016-11-30 10:35:21
    C++代码编写规范 1 头文件 1.1 使用头文件保护 使用#define进行头文件保护,而不使用微软的#pragma once。 为了保证唯一性,头文件保护的命名需要基于项目代码路径,比如Project\Src\Area\File.h 则文件的保护...

    C++代码编写规范

    1        头文件

    1.1    使用头文件保护

    使用#define进行头文件保护,而不使用微软的#pragma once。

    为了保证唯一性,头文件保护的命名需要基于项目代码路径,比如Project\Src\Area\File.h 则文件的保护应该像这样:

    #ifndefine         PROJECT_SRC_AREA_FILE_H

    #define              PROJECT_SRC_AREA_FILE_H

    #endif

     

    1.2    头文件依赖

    使用前置声明减少头文件的所要包含的文件数量,也就减少了需要重新编译文件的几率。

    对于需要在头文件里使用其他文件中定义的类时,如果只是使用类的声明而不是具体定义,应该是用前置声明代替包含整个文件,如下:

    使用class SomeClass;

    不使用 #include “SomeClass”。

     

    1.3    包含头文件的顺序

    顺序如下:C库、C++库、其他库.h、项目内的.h,如果次文件是cpp文件,那么要首先包含其对应的头文件,然后再按前述顺序。每个层级用空行分隔,同一层级的文件顺序按英文字母先后顺序排列,如下:

    #include“MyFile.h”  (如果次文件是cpp文件,首先包含自己的头文件)

     

    #include<stdio.h>

    #include<unistd.h>

     

    #include<iostream>

    #include<map>

    #include<string>

     

    #include“lib/Alpha.h”

    #include“lib/Beta.h”

    #include“other/zoo.h”

     

    #include“bar.h”

    #include“foo.h”

     

    2        作用域

    2.1    全局变量

    尽量不要使用全局变量,根据经验,全局变量起的作用往往仅是一个静态变量。如果非要使用全局变量,考虑使用单例模式代替。

    多线程中使用的全局变量,不要使用class类型(包括STL容器),避免class内部的实现非线程安全而导致bug。

     

    3        类

    3.1    声明顺序

    成员先后顺序:typedef、enum、常量、构造析构函数、成员函数,成员变量。

    域先后顺序:public、protected、private。

     

    比如:

    Class MyClass

    {

    public:

            

    public:

             voidFoo();

     

    protected:

             voidBar();

     

    private:

             voidFunc();

     

    public:

             intm_nCommonVar;

     

    private:

             intm_nMyVar;

    };

     

    3.2    构造函数

    构造函数只负责简单的初始化功能,如果需要进行有意义的初始化,请使用Init()函数。

    *严禁在构造函数中调用虚函数。

     

    3.3    拷贝构造函数

    仅需要拷贝一个对象时才定义拷贝构造函数,否则明确在private域中使用声明DISALLOW_COPY_AND_ASSIGN,避免编译器隐式声明的拷贝构造函数导致的不确定行为。如下:

    private:

    DISALLOW_COPY_AND_ASSIGN(MyClass);

     

    3.4    结构体和类

    只有数据时,使用结构体,否则使用类。

     

    3.5    继承

    尽量使用组合代替继承。

    如果类中有一个virtual函数,则析构函数必须声明为virtual。

    所有继承必须为public,私有继承使用其它实现方式替代。

     

    3.6    多重继承

    尽量避免使用多重继承,除非是COM。

     

    3.7    模板

    尽量不要使用模板,确定使用模板时确保一年后回头你还能看懂你的代码,并且调试这段模板无压力。

     

    3.8    操作符重载

    尽量避免使用操作符重载。

     

    4        其它特性

    4.1    异常处理

    不要使用异常处理。

     

    4.2    RTTI(运行时类型识别)

    不要使用RTTI,也就是dynamic_cast,非要使用只能说明设计有缺陷。

    原因:dynamic_cast会失败,而且不安全,难维护。

     

    4.3    前置自增和自减

    不考虑结果使用的情况下,尽量使用++i代替i++,因为++i效率更高。

     

    4.4    const使用

    尽量使用const修饰变量。                                                    

     

    5        注释

    5.1    头文件注释

    头文件开头部分必须使用注释,说明此文件的作者、作用等信息。

    即可证明你有多叼,也可让后人叼你。

    格式如下:

    /************************************************************************

    *

    * @description: XLBrowserAppSupport的Lua接口封装

    *

    * @author:      Gaoyunxiang

    * @date:        2015.11.10

    *

    * @last modified author:

    * @last modified date:

    *

    * @ copyright Xunlei Network 2015 -

    *

    *************************************************************************/

     

    5.2    类注释

    声明类之前需要使用类注释,说明此类的使用用途及注意事项

    如下:

    // 浏览器类。

    // 实现浏览器的常用功能,如导航等。

    // 需由浏览器工厂类来创建实例。

    class Browser{};

     

    5.3    函数注释

    重要或难理解的函数,需要在函数声明前加上注释。

    比如:

    // 做加法

    // nVar1:第一个加数

    // nVar2:第二个加数

    // 返回值:相加结果

    int Add(int nVar1, int nVar2);

     

    5.4    逻辑注释

    对于很难理解、重要、实现精彩的部分必须加上注释。

     

    5.5    TODO注释

    对于那些来不及实现、暂未实现、需要去实现的地方加上TODO注释。

    如下:

    // TODO: Fly to the moon.

     

    6        编码风格

    6.1    命名规则

    尽量不要使用缩写,严禁使用不明单词的缩写。

    类名:大写字母开头,每个单词首字母大写。

    函数名:大写字母开头,每个单词首字母大写

    变量名:首字母(通常为前缀)小写

     

    6.2    变量前缀

    前缀为小写,后面第一个字母为大写

    前缀的结尾为_时(如m_..),后面第一个字母为小写

    short/int/size_t..,加n,如int nVal =1;

    long,加l

    float/double..,加f

    bool/BOOL..,加b

    DWORD,加dw

    char*,加sz,如char *szVal= “abc”;

    wchar_t*,加wsz

    string,加str

    wstring,加wstr

    指针,加p

    long指针,加lp

    函数指针,加pfunc

    vector,加vec

    list,加list

    map,加map

    句柄类,加h

    类成员变量,加m_,如HWND m_hParentWnd= 0x66666666;

    全局变量,加g_

    静态变量,加s_

    常量,全部字母大写

    类名,加C

     

    6.3    缩进和换行

    使用空格代替table,在VS里将table设置成4个空格。每个级别进行4个空格的缩进。

    不要连续使用多于一次的换行。

     

    6.4    花括号

    另起一行使用。

     

    6.5    条件、循环、开关等语句

    关键字后面加空格再使用。

    比如:

    If ();

    while ();

    switch语句后的case:部分加作用域{}。

    7        其它注意事项

    7.1    堆分配和释放

    new/delete等堆操作,必须成对出现。

    尽量遵从谁分配谁释放的原则。

     

    7.2    引用计数

    AddRef()/Release()必须成对出现。

    尽量遵从谁分配谁释放的原则。

     

    7.3    指针、句柄使用完释放后必须设置成NULL。

    7.4    函数功能要单一,避免耦合多功能,严禁CreateAndNavigate这种函数。

    7.5    指针的空值比较使用NULL,而不是0。

    7.6    浮点数的零值比较严禁使用== 0。

    7.7    避免直接使用微软二次定义的数据类型,比如DWORD,使用其原始的unsigned long,方便跨平台。

     

     

    展开全文
  • 使用python制作ArcGIS插件(2)代码编写

    万次阅读 多人点赞 2016-10-10 08:40:43
    使用python制作ArcGIS插件(2)代码编写 by 李远祥  上一章节已经介绍了如何去搭建AddIn的界面,接下来要实现具体的功能,则到了具体的编程环节。由于使用的是python语言进行编程,则开发者需要掌握一些基本的...
    使用python制作ArcGIS插件(2)代码编写
    

    by 李远祥

        上一章节已经介绍了如何去搭建AddIn的界面,接下来要实现具体的功能,则到了具体的编程环节。由于使用的是python语言进行编程,则开发者需要掌握一些基本的python编程技能。python部分的知识不是本章节的重点,开发人员可以通过百度及其他方式去获取相关的python知识。ArcGIS在其帮助文档中也为我们提供了一些python的推荐教程,以下灰色文字部分是ArcGIS官方帮助中的一些文字截取。

    Python 是一种不受局限、跨平台的开源编程语言,它功能强大且简单易学。因而得到了广泛应用和支持。要了解有关 Python 的详细信息,请访问 python.org

    ArcGIS 9.0 社区中引入了 Python。此后,Python 被视为可供地理处理用户选择的脚本语言并得以不断发展。每个版本都进一步增强了 Python 体验,从而为您提供更多的功能以及更丰富、更友好的 Python 体验。

    ESRI 已将 Python 完全纳入 ArcGIS 中,并将其视为可满足我们用户社区需求的语言。下面仅介绍 Python 的部分优势:

    • 易于学习,非常适合初学者,也特别适合专家使用
    • 可伸缩程度高,适于大型项目或小型的一次性程序(称为脚本)
    • 可移植,跨平台
    • 可嵌入(使 ArcGIS 可脚本化)
    • 稳定成熟
    • 用户社区规模大

    Python 已延伸到 ArcGIS 中,成为了一种用于进行数据分析、数据转换、数据管理和地图自动化的语言,因而有助于提高工作效率。

    了解 Python

    以下包含的信息并不是 Python 的语言参考。而是根据一些用于说明如何编写地理处理脚本的示例和概念来介绍某些 Python 语法和行为。

    强烈建议您结合相应的 Python 参考书来进一步了解此处介绍的信息。对于 Python 初学者,建议使用以下两本书籍:《学习 Python》(Learning Python)(作者:Mark Lutz 和 David Ascher,出版社:O’Reilly & Associates)和《Python 核心编程》(Core Python Programming)(作者:Wesley J. Chun,出版社:Prentice Hall),这两本书都对该语言进行了详尽介绍,并且内容上不重叠。还有很多其他书籍也介绍了 Python 及其具体用途,其中有些新书会定期出版,因此可以探究可用的内容。Python 网站上提供了 Python 的完整文档,但内容很简明,主要是面向开发人员的。还有一个大型的 Python 在线社区,其中包含很多在线资源,您可通过 Python 主页访问这些资源。

    Python 教程

    如果您是 Python 的初学者,我们推荐您学习此处列出的一些外部教程。

    针对程序员的 Python 教程

    此处所列的外部教程主要面向以前学习过其他编程语言(Perl、Visual Basic、C)的人员。

     

        言归正传,在工程中如何进行编程。首先可以打开工程文件夹中的Instrall目录,用文本编辑器或者其他编辑工具打开.py文件。该py文件已经包含了一些初始化代码了,那我们则需要在事件或者界面初始化中加入适当的脚本即可。下图为设计器自动生成的代码

    import arcpy
    import pythonaddins
    
    class ButtonClass5(object):
        """Implementation for mytools_addin.button (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            pass
    
    class ButtonClass6(object):
        """Implementation for mytools_addin.button_1 (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            pass
    
    class ComboBoxClass1(object):
        """Implementation for mytools_addin.combobox (ComboBox)"""
        def __init__(self):
            self.items = ["item1", "item2"]
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'WWWWWW'
            self.width = 'WWWWWW'
        def onSelChange(self, selection):
            pass
        def onEditChange(self, text):
            pass
        def onFocus(self, focused):
            pass
        def onEnter(self):
            pass
        def refresh(self):
            pass
    
    class ComboBoxClass2(object):
        """Implementation for mytools_addin.combobox_1 (ComboBox)"""
        def __init__(self):
            self.items = ["item1", "item2"]
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'WWWWWW'
            self.width = 'WWWWWW'
        def onSelChange(self, selection):
            pass
        def onEditChange(self, text):
            pass
        def onFocus(self, focused):
            pass
        def onEnter(self):
            pass
        def refresh(self):
            pass

        可以看到该代码中已经为我们预留了两个combox的事件接口以及两个操作按钮的事件接口。

        那么使用什么样的代码编辑器呢,笔者认为可以根据各自的习惯去确定编辑器,个人比较喜欢比较轻量级的NotePad++,可以通过安装python插件来进行python代码的编写。当然,使用windows自带的文本编辑器也是可以编写,但效果不是十分理想。如果希望有代码提示和可调试,可以安装微软的VS2015,安装时选择python编辑器,可以实现Python和ArcPy的代码提示,并且可以对程序进行调试,不过VS2015就比较庞大了。初学者或者简单的应用,不妨可以考虑NotePad++这个轻量级的编辑工具。

        首选看到这个py文件中到了两个包,一个是ArcPy,另一个是pythonaddins,这两个都是ArcGIS自己维护的包。其中ArcPy允许我们对ArcGIS的功能进行编写,如ArcMap中所有的工具都能够在

    ArcPy中调用,同时ArcPy也会对原始的Python进行了一些简单的封装,将一些特殊的对象封装进去,便于开发。例如双击ArcMap的【裁剪】工具,调出该工具,可以看到其中有【工具帮助】的按钮,如下图所示

    image

        点击该按钮,可以进入到该工具的帮助中。帮助里面除了说该工具的使用方法和原理,每个参数的说明之外,还具有ArcPy的调用。如下图

    image

        例如该帮助中说明了如何通过arcpy去调用裁剪工具,每一个参数是如何设置的。可以看到,arcpy的调用非常的简洁,而且参数的形式是多样化的,可以是要素类和图层的名称,也可以是直接的获取的变量。关于arcpy的其他介绍,可以参考ArcMap的中文帮助,里面有非常细致的说明,可以帮助我们更加快捷的去设计插件。

        用NotePad++打开Install 目录下的.py文件,开始进行编辑。首选需要在说明字符集的问题,我们用到了中文字符,所以,必须在文件最顶出加入gbk字符集。然后需要定义一些变量,例如用作记录存储路径,裁剪数据,裁剪的图层等,如下代码

    #coding=gbk
    import arcpy
    import pythonaddins
    
    class AB:
        workPath=""     #记录保存路径
        listLayer=[]    #需要裁剪的图层列表
        ClipFeat=""     #用作裁剪的图层

    这里定义了一个类,用作记录一些基本的信息,这些变量会在后面分别给予赋值。

        接下来我们来看下来项怎么设置。插件的设想是在mxd里面获取一个图层作为裁剪用的范围图层,当然,这个图层是必须要先做好并加载到mxd中,combox的作用就是指定这个图层。但至于是哪个图层,那就需要先获取到地图文档中所有的图层,然后提供下拉列表。在列表中选中图层后,则将这个图层赋值给AB类的ClipFeat变量。这也是常规的编程做法了。看下面代码是怎么实现的。Combox已经定义后一些列的事件了,我们分别在事件里面加入python代码。

    class ComboBoxClass1(object):   #选择用于裁剪的图层
        """Implementation for mytools_addin.combobox (ComboBox)"""
        def __init__(self):
            mxd = arcpy.mapping.MapDocument('current')
            df = arcpy.mapping.ListDataFrames(mxd, "图层")[0]
            for lyr in arcpy.mapping.ListLayers(mxd,"",df):
                AB.listLayer.append(lyr.name)
            self.items = AB.listLayer
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'WWWWWW'
            self.width = 'WWWWWW'
        def onSelChange(self, selection):
            AB.ClipFeat = selection
            print AB.ClipFeat
            pass
        def onEditChange(self, text):
            pass
        def onFocus(self, focused):
            pass
        def onEnter(self):
            pass
        def refresh(self):
            pass

        上述代码可以看到,在combox的初始化中,利用arcpy.mapping的方式获取mxd文档中所有的图层,并将这些图层加入到AB类的listLayer数组中,用数组来记录这些图层,然后将这个数组赋值给combox的items,这样就能在combox中看到这个mxd的所有图层了。

        onSelChange 事件是用来响应选择操作的,在这个combox中,需要从mxd里面选择一个图层来用作指定裁剪范围,可以看到,直接将选中的值赋值给 AB.ClipFeat。其他事件就不需要再给代码了。从这个例子可以看到,python就像积木一样,将arcgis的一些功能快速的堆积在一起,这就是我们选择使用python做开发的原因。

        第二个combox是用于现实裁剪后的数据保存的路径。由于设计器中没有给出toolbox上的label或text控件,所以,只能使用combox来现实我们选择的保存路径。这个combox就什么都不用做,保留原来的代码就行了。我们会在选择后路径后会给予它路径值作为现实,其原始代码如下

    class ComboBoxClass2(object):  #用于现实路径
        #用于显示路径
        """Implementation for mytools_addin.combobox_1 (ComboBox)"""
        def __init__(self):
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'WWWWWW'
            self.width = 'WWWWWW'
        def onSelChange(self, selection):
            pass
        def onEditChange(self, text):
            pass
        def onFocus(self, focused):
            pass
        def onEnter(self):
            pass
        def refresh(self):
            pass

        接下来就是在选择路径的按钮下弹出选择文件夹或者gdb的路径了(fileGDB也是个文件夹)。如果是选择到文件级别,那保存的数据就是shapefile,如果选择的文件夹刚好是fileGDB,arcpy则会自动将数据保存到gdb中去,这一点是非常人性化的,不需要些代码去识别和控制到底是文件夹还是gdb,更不用去控制导出的数据格式。看以下代码

    class ButtonClass5(object):
        #选择存储的路径
        """Implementation for mytools_addin.button (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            AB.workPath=pythonaddins.OpenDialog("选择存储路径")
            ComboBoxClass2.items=[AB.workPath,'']
            pass

    在onclick事件中,使用 pythonaddins.OpenDialog 来打开windows路径选择器,这些界面操作都由pythonaddins 包实现了,我们只需要简单调用就行,选中路径后将路径赋值给A B.workPath ,先记录下来。然后不忘初衷的是,在 ComboBoxClass2.items 中显示指定的路径。

        前面的这些代码都没能实现裁剪,都是一些交互性的脚本代码,那接下来这个裁剪功能才是核心的。在点击之行按钮后,我们需要调用裁剪功能去进行批量裁剪。那么,涉及到裁剪的各个变量,我们都已经在上述的交互中完成。来看看批量裁剪的功能,就是利用ClipFeat对listLayer每一个元素进行裁剪操作,并将结果保存在workpath中,命名的方式与图层名保持一致。

    class ButtonClass6(object):
        #执行最终的操作
        """Implementation for mytools_addin.button_1 (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            mxd = arcpy.mapping.MapDocument('current')
            df = arcpy.mapping.ListDataFrames(mxd, "图层")[0]
            for lyr in arcpy.mapping.ListLayers(mxd,"",df):
                outStr=u'正在裁剪'+lyr.name+u'...'
                resultFeats = AB.workPath+"/"+lyr.name
                arcpy.analysis.Clip(lyr.dataSource, AB.ClipFeat,resultFeats) #核心代码
            print "裁剪结束"
            pass

        可以看到,非常核心的裁剪代码就是arcpy.analysis.Clip 功能,这个功能就是我们上面说的toolbox工具箱里面的工具,早已经在arcgis里面实现,只需要一个语句进行调用即可。关键的部分我们使用了for循环来实现遍历,做成了批量裁剪。与toolbox工具里面的批量处理不一样的是,这个批量裁剪的工具裁剪出来的名称可以有我们自己来处理,这就避免了所有的结果带_clip的后缀。

    下面来看这个工具的所有代码,非常简介的几行代码实现了一个简单而实用的工具。

    #coding=gbk
    import arcpy
    import pythonaddins
    
    class AB:
        workPath=""     #记录保存路径
        listLayer=[]    #需要裁剪的图层列表
        ClipFeat=""     #用作裁剪的图层
    
    class ButtonClass5(object):
        #选择存储的路径
        """Implementation for mytools_addin.button (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            AB.workPath=pythonaddins.OpenDialog("选择存储路径")
            ComboBoxClass2.items=[AB.workPath,'']
            pass
    
    class ButtonClass6(object):
        #执行最终的操作
        """Implementation for mytools_addin.button_1 (Button)"""
        def __init__(self):
            self.enabled = True
            self.checked = False
        def onClick(self):
            mxd = arcpy.mapping.MapDocument('current')
            df = arcpy.mapping.ListDataFrames(mxd, "图层")[0]
            for lyr in arcpy.mapping.ListLayers(mxd,"",df):
                outStr=u'正在裁剪'+lyr.name+u'...'
                resultFeats = AB.workPath+"/"+lyr.name
                arcpy.analysis.Clip(lyr.dataSource, AB.ClipFeat,resultFeats) #核心代码
            print "裁剪结束"
            pass
    
    class ComboBoxClass1(object):   #选择用于裁剪的图层
        """Implementation for mytools_addin.combobox (ComboBox)"""
        def __init__(self):
            mxd = arcpy.mapping.MapDocument('current')
            df = arcpy.mapping.ListDataFrames(mxd, "图层")[0]
            for lyr in arcpy.mapping.ListLayers(mxd,"",df):
                AB.listLayer.append(lyr.name)
            self.items = AB.listLayer
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'WWWWWW'
            self.width = 'WWWWWW'
        def onSelChange(self, selection):
            AB.ClipFeat = selection
            print AB.ClipFeat
            pass
        def onEditChange(self, text):
            pass
        def onFocus(self, focused):
            pass
        def onEnter(self):
            pass
        def refresh(self):
            pass
    
    class ComboBoxClass2(object):  #用于现实路径
        #用于显示路径
        """Implementation for mytools_addin.combobox_1 (ComboBox)"""
        def __init__(self):
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'WWWWWW'
            self.width = 'WWWWWW'
        def onSelChange(self, selection):
            pass
        def onEditChange(self, text):
            pass
        def onFocus(self, focused):
            pass
        def onEnter(self):
            pass
        def refresh(self):
            pass

       代码实现完后,确保没有问题,记得重新执行一下工程目录下的makeaddin.py 脚本,生成一个新的esriaddin文件。在安装这个新的插件之前,需要先在加载项管理器中删除原来的插件,再重新安装这个新的插件。直到这一步为止,这个插件基本就实现完成了。如果想更进一步,那就在执行完之后将mxd里面的所有图层的数据源设置为裁剪后的数据源,这样就实现所见即得的结果了。

        插件源码和测试数据下载地址链接:http://pan.baidu.com/s/1i58tewX 密码:3cv3

    展开全文
  • 单元测试代码编写

    千次阅读 2011-10-21 00:47:13
    实际上,单元测试与代码编写是“一体两面”的关系,编码时对上述三种输入都是必须考虑的,否则代码的健壮性就会成问题。  白盒覆盖  上面所说的测试数据都是针对程序的功能来设计的,就是所谓的 ...

          单元测试是在软件开发过程中要进行的最低级别的测试活动,在单元测试活动中,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。 单元测试不仅仅是作为无错编码一种辅助手段在一次性的开发过程中使用,单元测试必须是可重复的,无论是在软件修改,或是移植到新的运行环境的过程中。因此,所有的测试都必须在整个软件系统的生命周期中进行维护。

          多数讲述单元测试的文章都是以Java为例,本文以C++为例,后半部分所介绍的单元测试工具也只介绍C++单元测试工具。下面的示例代码的开发环境是VC6.0。

    产品类

      class CMyClass

      {

      public:

      int Add(int i, int j);

      CMyClass();

      virtual ~CMyClass();

      private:

      int mAge; //年龄

      CString mPhase; //年龄阶段,如"少年","青年"

      };

      建立对应的测试类CMyClassTester,为了节约编幅,只列出源文件的代码:

      void CMyClassTester::CaseBegin()

      {

      //pObj是CMyClassTester类的成员变量,是被测试类的对象的指针,

      //为求简单,所有的测试类都可以用pObj命名被测试对象的指针。

      pObj = new CMyClass();

      }

      void CMyClassTester::CaseEnd()

      {

      delete pObj;

      }

      测试类的函数CaseBegin()和CaseEnd()建立和销毁被测试对象,每个测试用例的开头都要调用CaseBegin(),结尾都要调用CaseEnd()。

    产品函数

      接下来,我们建立示例的产品函数:

      int CMyClass::Add(int i, int j)

      {

      return i+j;

      }

      和对应的测试函数:

      void CMyClassTester::Add_int_int()

      {

      }

      把参数表作为函数名的一部分,这样当出现重载的被测试函数时,测试函数不会产生命名冲突。下面添加测试用例:

      void CMyClassTester::Add_int_int()

      {

      //第一个测试用例

      CaseBegin();{ //1

      int i = 0; //2

      int j = 0; //3

      int ret = pObj->Add(i, j); //4

      ASSERT(ret == 0); //5

      }CaseEnd(); //6

      }

    解释

      第1和第6行建立和销毁被测试对象,所加的{}是为了让每个测试用例的代码有一个独立的域,以便多个测试用例使用相同的变量名。

      第2和第3行是定义输入数据,第4行是调用被测试函数,这些容易理解,不作进一步解释。第5行是预期输出,它的特点是当实际输出与预期输出不同时自动报错,ASSERT是VC的断言宏,也可以使用其他类似功能的宏,使用测试工具进行单元测试时,可以使用该工具定义的断言宏。

      示例中的格式显得很不简洁,2、3、4、5行可以合写为一行:ASSERT(pObj->Add(0, 0) == 0);但这种不简洁的格式却是老纳极力推荐的,因为它一目了然,易于建立多个测试用例,并且具有很好的适应性,同时,也是极佳的代码文档,总之,老纳建议:输入数据和预期输出要自成一块。

      建立了第一个测试用例后,应编译并运行测试,以排除语法错误,然后,使用拷贝/修改的办法建立其他测试用例。由于各个测试用例之间的差别往往很小,通常只需修改一两个数据,拷贝/修改是建立多个测试用例的最快捷办法。

     

    测试用例设计

     

    下面谈谈测试用例设计。前面已经说了,测试用例的核心是输入数据。预期输出是依据输入数据和程序功能来确定的,也就是说,对于某一程序,输入数据确定了,预期输出也就可以确定了,至于生成/销毁被测试对象和运行测试的语句,是所有测试用例都大同小异的,因此,我们讨论测试用例时,只讨论输入数据。

      前面说过,输入数据包括四类:参数、成员变量、全局变量、IO媒体,这四类数据中,只要所测试的程序需要执行读操作的,就要设定其初始值,其中,前两类比较常用,后两类较少用。显然,把输入数据的所有可能取值都进行测试,是不可能也是无意义的,我们应该用一定的规则选择有代表性的数据作为输入数据,主要有三种:正常输入,边界输入,非法输入,每种输入还可以分类,也就是平常说的等价类法,每类取一个数据作为输入数据,如果测试通过,可以肯定同类的其他输入也是可以通过的。下面举例说明:

      正常输入

      例如字符串的Trim函数,功能是将字符串前后的空格去除,那么正常的输入可以有四类:前面有空格;后面有空格;前后均有空格;前后均无空格。

      边界输入

      上例中空字符串可以看作是边界输入。

      再如一个表示年龄的参数,它的有效范围是0-100,那么边界输入有两个:0和100。

      非法输入

      非法输入是正常取值范围以外的数据,或使代码不能完成正常功能的输入,如上例中表示年龄的参数,小于0或大于100都是非法输入,再如一个进行文件操作的函数,非法输入有这么几类:文件不存在;目录不存在;文件正在被其他程序打开;权限错误。

      如果函数使用了外部数据,则正常输入是肯定会有的,而边界输入和非法输入不是所有函数都有。一般情况下,即使没有设计文档,考虑以上三种输入也可以找出函数的基本功能点。实际上,单元测试与代码编写是“一体两面”的关系,编码时对上述三种输入都是必须考虑的,否则代码的健壮性就会成问题。

      白盒覆盖

      上面所说的测试数据都是针对程序的功能来设计的,就是所谓的黑盒测试。单元测试还需要从另一个角度来设计测试数据,即针对程序的逻辑结构来设计测试用例,就是所谓的白盒测试。在老纳看来,如果黑盒测试是足够充分的,那么白盒测试就没有必要,可惜“足够充分”只是一种理想状态,例如:真的是所有功能点都测试了吗?程序的功能点是人为的定义,常常是不全面的;各个输入数据之间,有些组合可能会产生问题,怎样保证这些组合都经过了测试?难于衡量测试的完整性是黑盒测试的主要缺陷,而白盒测试恰恰具有易于衡量测试完整性的优点,两者之间具有极好的互补性,例如:完成功能测试后统计语句覆盖率,如果语句覆盖未完成,很可能是未覆盖的语句所对应的功能点未测试。

      白盒测试针对程序的逻辑结构设计测试用例,用逻辑覆盖率来衡量测试的完整性。逻辑单位主要有:语句、分支、条件、条件值、条件值组合,路径。语句覆盖就是覆盖所有的语句,其他类推。另外还有一种判定条件覆盖,其实是分支覆盖与条件覆盖的组合,在此不作讨论。跟条件有关的覆盖就有三种,解释一下:条件覆盖是指覆盖所有的条件表达式,即所有的条件表达式都至少计算一次,不考虑计算结果;条件值覆盖是指覆盖条件的所有可能取值,即每个条件的取真值和取假值都要至少计算一次;条件值组合覆盖是指覆盖所有条件取值的所有可能组合。老纳做过一些粗浅的研究,发现与条件直接有关的错误主要是逻辑操作符错误,例如:||写成&&,漏了写!什么的,采用分支覆盖与条件覆盖的组合,基本上可以发现这些错误,另一方面,条件值覆盖与条件值组合覆盖往往需要大量的测试用例,因此,在老纳看来,条件值覆盖和条件值组合覆盖的效费比偏低。老纳认为效费比较高且完整性也足够的测试要求是这样的:完成功能测试,完成语句覆盖、条件覆盖、分支覆盖、路径覆盖。做过单元测试的朋友恐怕会对老纳提出的测试要求给予一个字的评价:晕!或者两个字的评价:狂晕!因为这似乎是不可能的要求,要达到这种测试完整性,其测试成本是不可想象的,不过,出家人不打逛语,老纳之所以提出这种测试要求,是因为利用一些工具,可以在较低的成本下达到这种测试要求,后面将会作进一步介绍。

      关于白盒测试用例的设计,程序测试领域的书籍一般都有讲述,普通方法是画出程序的逻辑结构图如程序流程图或控制流图,根据逻辑结构图设计测试用例,这些是纯粹的白盒测试,不是老纳想推荐的方式。老纳所推荐的方法是:先完成黑盒测试,然后统计白盒覆盖率,针对未覆盖的逻辑单位设计测试用例覆盖它,例如,先检查是否有语句未覆盖,有的话设计测试用例覆盖它,然后用同样方法完成条件覆盖、分支覆盖和路径覆盖,这样的话,既检验了黑盒测试的完整性,又避免了重复的工作,用较少的时间成本达到非常高的测试完整性。不过,这些工作可不是手工能完成的,必须借助于工具,后面会介绍可以完成这些工作的测试工具。

    编辑本段单元测试工具

      现在开始介绍单元测试工具,分别按编程语言进行分组介绍。

    C/C++

      CppUnit

      首先是CppUnit,这是C++单元测试工具的鼻祖,免费的开源的单元测试框架。由于已有一众高人写了不少关于CppUnit的很好的文章,老纳就不现丑了,想了解CppUnit的朋友,建议读一下Cpluser 所作的《CppUnit测试框架入门》,。该文也提供了CppUnit的下载地址。

      C++Test

      然后介绍C++Test,这是Parasoft公司的产品。[C++Test是一个功能强大的自动化C/C++单元级测试工具,可以自动测试任何C/C++函数、类,自动生成测试用例、测试驱动函数或桩函数,在自动化的环境下极其容易快速的将单元级的测试覆盖率达到100%]。[]内的文字引自,这是华唐公司的网页。老纳想写些介绍C++Test的文字,但发现无法超越华唐公司的网页上的介绍,所以也就省点事了,想了解C++Test的朋友,建议访问该公司的网站。华唐公司代理C++Test,想要购买或索取报价、试用版都可以找他们。

      Visual Unit

      最后介绍Visual Unit,简称VU,这是国产的单元测试工具,据说申请了多项专利,拥有一批创新的技术,不过老纳只关心是不是有用和好用。[自动生成测试代码 快速建立功能测试用例 程序行为一目了然 极高的测试完整性 高效完成白盒覆盖 快速排错 高效调试 详尽的测试报告]。[]内的文字是VU开发商的网页上摘录的,。前面所述测试要求:完成功能测试,完成语句覆盖、条件覆盖、分支覆盖、路径覆盖,用VU可以轻松实现,还有一点值得一提:使用VU还能提高编码的效率,总体来说,在完成单元测试的同时,编码调试的时间还能大幅度缩短。算了,不想再讲了,老纳显摆理论、介绍经验还是有兴趣的,因为可以满足老纳好为人师的虚荣心,但介绍工具就觉得索然无味了,毕竟工具好不好用,合不合用,要试过才知道,还是自己去开发商的网站看吧,可以下载演示版,还有演示课件。

      gtest

       gtest测试框架是在不同平台上(Linux,Mac OS X,Windows,Cygwin,Windows CE和Symbian)为编写C++测试而生成的。它是基于xUnit架构的测试框架,支持自动发现测试,丰富的断言集,用户定义的断言,death测试,致命与非致命的失败,类型参数化测试,各类运行测试的选项和XML的测试报告。需要详细了解的朋友可以参阅《玩转Google单元测试框架gtest系列》该篇文章。

    Java

      JUnit

      JUnit 是 Java 社区中知名度最高的单元测试工具。它诞生于 1997 年,由 Erich Gamma 和 Kent Beck 共同开发完成。其中 Erich Gamma 是经典著作《设计模式:可复用面向对象软件的基础》一书的作者之一,并在 Eclipse 中有很大的贡献;Kent Beck 则是一位极限编程(XP)方面的专家和先驱。JUnit 设计的非常小巧,但是功能却非常强大。JUnit ——是一个开发源代码的Java测试框架,用于编写和运行可重复的测试。他是用于单元测试框架体系xUnit的一个实例(用于java语言)。主要用于白盒测试,回归测试。

      JUnit的好处和JUnit单元测试编写原则:

      好处:可以使测试代码与产品代码分开;针对某一个类的测试代码通过较少的改动便可以应用于另一个类的测试;易于集成到测试人员的构建过程中,JUnit和Ant的结合可以实施增量开发;JUnit是公开源代码的,可以进行二次开发;可以方便地对JUnit进行扩展;

      编写原则:是简化测试的编写,这种简化包括测试框架的学习和实际测试单元的编写;是使测试单元保持持久性;是可以利用既有的测试来编写相关的测试;

      有兴趣的朋友可以下下来仔细研究下。

      JUnit-addons

      对JUnit的一些补充,比如设置、获取被测试对象的私有属性的值,调用被测试对象的私有方法等。

      常用类:junitx.util.PrivateAccessor

      Spring 测试框架

      可以测试基于Spring的应用,通过配置文件和注解自动组装需要的单元测试对象。

      提供了一些常用的J2EE Mock对象,比如HttpSession的Mock类等。

      可以支持数据库自动回滚,以防止对数据库的单元测试(插入,删除等)不可重复执行,防止修改数据库状态等。

      DJUnit

      通过代码自动产生Mock对象,省去了自己手动编写N多的Mock类。

      此外,它的Eclipse插件还可以做到测试覆盖率、分支统计。

      EasyMock

      功能同DJUnit,也是通过编程自动Mock掉与测试对象无关的类,方法。

    展开全文
  • LaTeX的伪代码编写技巧

    千次阅读 2018-02-09 16:16:56
    PIAPIA是一个象声词,更是一种生活态度... 果断!干脆!强势!Latex使用小结开始在论文写作中使用Latex,整理一下手册中常用的以及在网上搜集到的一些资料,以便以后查阅。 \textrm 公式里面出现文本格式\label{} ...

    PIA

    PIA是一个象声词,更是一种生活态度... 果断!干脆!强势!

    Latex使用小结

    开始在论文写作中使用Latex,整理一下手册中常用的以及在网上搜集到的一些资料,以便以后查阅。

     

    \textrm 公式里面出现文本格式

    \label{} 加标签

    \ref{} 引用

    \eqref{} 公式引用

    \mathbf{} 粗体(数学符号)

    \textbf{} 粗体(文本)

    \emph{} 斜体强调

     

     

    公式的编辑可以借助在线公式编辑器,所见即所得

    http://zh.numberempire.com/texequationeditor/equationeditor.php

     

     

    插入算法

    参照 http://www.ctex.org/documents/packages/verbatim/index.htm 中的algorithms章节,下面举例说明需要注意的几点

     

    首先引入几个需要用到的包

    \usepackage{algorithm} %format of the algorithm 
    \usepackage{algorithmic} %format of the algorithm 
    \usepackage{multirow} %multirow for format of table 
    \usepackage{amsmath} 
    \usepackage{xcolor}

    重新定义require和ensure命令对应的关键字(此处将默认的Require/Ensure自定义为Input/Output)

    \renewcommand{\algorithmicrequire}{\textbf{Input:}} 
    \renewcommand{\algorithmicensure}{\textbf{Output:}}

    分析一下示例:

    \begin{algorithm} %算法开始 
    \caption{Sample algorithm} %算法的题目 
    \label{alg1} %算法的标签 
    \begin{algorithmic}[1] %此处的[1]控制一下算法中的每句前面都有标号 
    \REQUIRE Text:Today is a good day. Variables:$u,v,w$. $G=(V,E)$ %输入条件(此处的REQUIRE默认关键字为Require,在上面已自定义为Input) 
    \ENSURE Something... %输出结果(此处的ENSURE默认关键字为Ensure在上面已自定义为Output) 
    % if-then-else 
    \IF{some condition is true} 
    \STATE do some processing 
    \ELSIF{some other condition is true} 
    \STATE do some different processing 
    \ELSE 
    \STATE do the default actions 
    \ENDIF 
    % for loop 
    \FOR{$i=0$ to $10$} 
    \STATE carry out some processing 
    \ENDFOR 
    \FORALL{$i$ such that $0\leq i\leq 10$} 
    \STATE carry out some processing 
    \ENDFOR 
    % while-loop 
    \WHILE{some condition holds} 
    \STATE carry out some processing 
    \ENDWHILE 
    % repeat-until loop 
    \REPEAT 
    \STATE carry out some processing 
    \UNTIL{some condition is met} 
    % infinite loop 
    \LOOP 
    \STATE this processing will be repeated forever 
    \ENDLOOP

    \end{algorithmic} 
    \end{algorithm}

     

    输出结果如下所示:

    未命名

     

     

    先记到这里,附上几个有用的链接

    学习LaTeX http://latex.yo2.cn/articles/latex-learning12.html

    CTEX - 在线文档 - TeX/LaTeX 常用宏包 http://www.ctex.org/documents/packages/verbatim/index.htm

    Latex在线公式编辑器 http://zh.numberempire.com/texequationeditor/equationeditor.php

    展开全文
  • scrapy--爬虫代码编写步骤

    千次阅读 2018-05-22 17:49:47
    一、编写步骤1、新建工程目录进入打算存储代码的目录中,命令行运行下列命令:scrapy startproject 目录或爬虫名称2、用pycharm打开此目录,可看到如下目录结构3、items.py文件中定义item,主要是网页中要提取的一个...
  • Excel VBA(WPS专业版)安装及代码编写

    万次阅读 多人点赞 2018-04-14 11:37:29
    > 最后更新: 2020/7/18 > 以前用的wps是需要自己单独再安装vba插件的,现在更新的wps都是自带vba的,在菜单栏>开发工具可以看到,... 时隔两年,已经做了不少开发工作,能站在比之前更高的角度去写文档和教写代码了;
  • HTML代码编写的网页出现中文乱码问题解决方案

    万次阅读 多人点赞 2019-03-18 17:07:05
    2.解决方案 (1)在HTML文件头中增加下面代码: 而这段代码在一个完整的HTML页面中的位置是这样的:  Jeds Html website 其中 标签中各大元素,属性都做了说明:
  • 代码编写的iPhone程序教程源码4 UIView UILabel UIButton 这篇教程是关于完全用代码编写iPhone的视图界面的教程(并不涉及Interface Builder和Storyboard的使用)。 教程里从教读者怎样使用Xcode创建一个...
  • 用c语言代码编写的游戏“简易五子棋”

    万次阅读 多人点赞 2016-02-16 21:48:05
    编译代码 #include #include #include #include #define MAXIMUS 15 //定义棋盘大小 int p[MAXIMUS][MAXIMUS];//存储对局信息 char buff[MAXIMUS*2+1][MAXIMUS*4+3];//...
  • Android Studio 中的快捷键是非常多的,熟练使用可以极大程度上的提高代码编写效率。它和Eclipse的快捷键有所不同,虽然可以在AS上使用Eclipse中的快捷键,但是难免有所冲突,而且不能使用AS中的新增的更人性化的...
  • 给大家推荐一个用jQuery编写的滚动字幕程序,有的人也叫跑马灯程序。这个程序相对于传统跑马灯程序增加了文字滚动速度调节、显示一段时间后消失、鼠标移入停止、鼠标移出继续滚动等功能,同时修改了刷新界面时会先...
  • 编写自文档化代码

    千次阅读 2016-01-19 21:27:57
    创建优秀的代码意味着创建良好的文档化了的代码。我们编写代码的原因是要表达一套清晰的指令——不仅仅是对电脑,也是对那些以后需要维护或拓展这些指令的可怜傻瓜们。
  • 但是,近几日在看一些公司内部文档以及网上的一些开源代码,对这些代码的编写风格感触颇深,大凡真正参与过sourceforge上正规开源项目开发的人,一定对他们的代码编写格式记忆尤新!再看看目前手头上看得这份从网上...
  • XML代码编写(一)

    千次阅读 2019-08-27 08:00:55
    XML代码编写(一) XML概念  ExtensibleMarkupLanguage,翻译过来为可扩展标记语言。Xml技术是w3c组织发布的,目前推荐遵循的是W3C组织于2000发布的XML1.0规范。 学习XML的目的  在现实生活中大量存在有关系的...
  • typora编写md文件文字设置颜色

    千次阅读 2020-10-13 13:21:27
    typora编写md文件文字设置颜色 AutoHotKey是一款著名的windows系统快捷键设置的软件,轻便小巧。 官方下载: https://autohotkey.com/download/ahk-install.exe 1. 先安装AutoHotKey 2. 打开记事本,把如下内容复制...
  • --给文字添加中划线--> android:id="@+id/TextView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="给文字添加中划线" android:textSize="30sp" android:...
  • 利用VSCode编写ArcPy代码

    千次阅读 2017-11-03 16:38:23
    利用VSCode编写ArcPy代码 本文导读:python作为脚本语言,立足于后台代码,一直都缺乏IDE编辑器。随着互联网技术和大数据的兴起,越来越多人重视python语言,甚至在一些专业性很强的应用端上逐步将python语言作为...
  • 它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: 去年年底,该插件已经改名为Emmet。但Emmet不只改名,还带来了一些新特性。本文就来直观地演示给你。 一、快速...
  • 求大神指点怎样编写程序让c循环结束的条件是碰到文字?循环代码怎么写啊?
  • 功能:编写一个程序,输出一个字符串中的大写英文字母数,小写英文字母数以及非英文字母数。
  • Python编写简单“跑马灯”文字

    千次阅读 2019-05-22 20:15:56
    import os import time def main(): words = '杭州金博科技有限公司承办' while True: os.system('clear') print(words) time.sleep(0.5) words = words[1:] + words[0] if __name__ ==...
  • Emmet:HTML/CSS代码快速编写神器

    千次阅读 2014-04-04 22:17:48
    它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示:    Zen coding下的编码演示 去年年底,该插件已经改名为Emmet。但Emmet不只改名,还带来了一些新特性。...
  • 1. 编写一个程序,输出一个字符串中的大写英文字母数,小写英文字母数以及非英文字母数。(字符串可以在main方法中指定) import java.util.*; public class STring { void count(String s) { int n=s....
  • 两行代码搞定python OCR图像文字识别

    千次阅读 2019-03-22 14:39:32
    3、编写py代码: import pytesseract from PIL import Image pytesseract.pytesseract.tesseract_cmd = 'D://ocr/Tesseract-OCR/tesseract.exe' text = pytesseract.image_to_string(Image.open('D://ocr/...
  • mmet的前身是大名鼎鼎的Zen coding,如果...它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示:    Zen coding下的编码演示 去年年底,该插件已经改名为E
  • 求一个python的相册源代码,可以实现文字介绍图片功能。 比如:下边是图片,上边是文字的介绍,同时可以实现切换图片和文字的功能。
  • 编写程序——代码的排版

    千次阅读 2014-11-15 22:07:47
    代码排版是每个软件工程师都要面对的问题。好的排版不仅可以让读代码的人感到赏心悦目,更重要的是可以从代码格式中发现程序的内在逻辑结构。这就好像文章、博客的一样,它们会通过分段、空白行、标点符号等各种元素...
  • sublime text3 快速编写 HTML/CSS代码

    万次阅读 2018-02-24 19:36:00
    转自:...它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: Zen coding下的编码演示一、快速编写HTML代码 1. 初始化 HTML文档需要包含一些固定...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 222,781
精华内容 89,112
关键字:

代码编写文字