单元测试的方法以及单元测试的环境,但是手工单元测试时,测试用 例、结果判断都需要人工干预,并且测试过程中非法分支会对源代码造成破坏,导致测试用例不可 重用,这样效率会很低。所以我们需要使用自动化测试的方法来进行单元测试,即 BVT(Build Verification Test,创建确认测试)。 目前市场关于单元自动化测试的工具也较多,本书主要介绍 CppUnit 的使用。 CppUnit 是一个用 C++语言实现的单元测试框架,属于 XUnit 系列中的一员。CppUnit 采用了 BTV 的理念,用于面向对象 C++程序的单元测试的框架。它提供了一系列的头文件和静态库,采 用 CppUnit 所提供的单元测试框架,可以很方便地开发测试用例,并实现单元测试的“自测试”。 一方面使用 CppUnit 开发出来的测试用例是固化的,对同一个功能多次执行的测试用例是完全相同 的,并实现了测试的自动化,在测试用例的执行过程中不需要测试人员干预;另一方面 CppUnit
采用断言来判断测试用例的执行结果,并可将执行结果写入一个文本文件中。 CppUnit 作为一个成熟的单元测试框架,具有以下特点: (1)测试代码就是普通的 C++代码,不需要学习新的测试脚本。 (2)在测试期间测试代码和源代码一起运行,一旦发现错误,可以及时增加测试用例不停地 进行测试,有利于发现更多的问题,更好地保证代码的质量。 (3)由于框架成熟,测试过程中就可以将更多的精力放在“桩函数的统一”“可回归的单元测 试”的目标上。 (4)由于 C++类有私有、保护成员,一般的外部单元测试工具对于 C++的支持都不是很好, 但 CppUnit 就是针对 C++的,且采用了很直接的做法,只要在被测类的头文件中声明测试类是其友 元,就可以在测试中得心应手。 (5)CppUnit 是开源代码,测试过程中可以增加它的功能。 CppUnit 单元测试框架中的主要概念如下: 被测试类(CUT):被测试的类,该类的一个实例对象或者类本身作为测试的对象。 被测试方法:被测试的类中的成员方法。 测试用例(test case):用来测试一个功能是否正确的一系列测试执行,是测试执行和统计的最 基本单位。 测试工厂:一般给一个被测试类定义一个测试工厂,对该被测试类的被测试方法的测试用例和 数据进行组装。 测试装置(test fixture):容纳多个测试方法以及相关测试数据的类,它可以为多个测试方法准 备相关数据、测试上下文,进行公共的初始化和后处理。 测试套(test suite):相关测试用例的集合,测试套之间可以互相嵌套,即一个测试套可以包 含一些测试用例,也可以包含其他测试套。一般来说,测试套和被测试的方法对应,并且需要把测 试套定义为测试装置类。 测试方法(test method):以一个函数形式表现出来的独立的测试执行。每个测试用例对应一 个测试方法,但又不完全等同于测试方法。比如进行继承类的测试,虽然父类和子类有完全相同的 测试方法,但在父类和子类中对应于同样测试方法的测试用例是不相干的。 使用 CppUnit 单元测试框架进行单元自动化测试的步骤如下: 第一步:编译 CppUnit 静态库文件*.lib 和动态库文件*.dll。 CppUnit 提供了两套框架库:一个为静态的 lib;一个为动态的 dll。Cppunit 工程为静态 lib, cppunit_dll 工程为动态 dll 和 lib。 进入 CppUnit 程序包,打开 src 文件,打开 CppUnitLibraries.dsw 程序,在 Microsoft Visual Studio 6.0 编辑器中单击“工程”下拉菜单,先选择“设置活动工程”菜单项,将当前活动工程分别设置 为 cppunit 和 cppunit_dll 并进行编译,生成的静态文件*.lib 和动态库文件*.dll 都会输出到 lib 文件 夹中。还有一个工程 TestRunner 需要注意,编译该工程也会输出一个 dll 文件,该 dll 文件提供了 一个基于 GUI 方式的测试环境。
第二步:建立基于对话框的工程。 打开 Microsoft Visual Studio 6.0 编辑器,在“文件”下拉菜单中选择“新建”菜单项,创建一 个基于dialog的工程,如图10-13所示,在新建对话框中设置好工程名(假设设置的工程名为cppunit) 和存放位置,单击“确定”按钮。
弹出如图 10-14 所示的对话框,选择“基本对话”单选项,并单击“完成”按钮。
第三步:屏蔽工程对话框。 在工程 cppunit.cpp 工程文件中,找到 BOOL CCppunitApp::InitInstance()方法,将如下代码注释掉:
因为测试过程中需要调用 CppUnit 自带的 GUI 对话框(如图 10-15 所示),所以需要将创建时 生成的基于对话框的应用程序类型注释掉。
第四步:实现 CppUnit 测试执行器,并将测试工厂添加到测试执行器中。 找到 BOOL CCppunitApp::InitInstance()方法,添加如下代码:
由于在 BOOL CCppunitApp::InitInstance()中引用了 CppUnit 的类,所以在文件开始处要添加如 下头文件:
#include <cppunit/extensions/TestFactoryRegistry.h> #include <cppunit/ui/mfc/TestRunner.h>
第五步:添加被测对象。 选择菜单“工程”→“添加工程”→“文件”选项,将被测对象所在文件(*.h 和*.cpp)添加 到工程中(假设添加的被测试对象为 Iscodeline.cpp 文件)。 第六步:在工程中为被测对象 Iscodeline 编写测试类文件 CounterTest(可以自定义文件名)。 选择菜单“工程”→“添加工程”→“新建”选项,分别在源文件和头文件中新建 CounterTest.cpp 源文件和 CounterTest.h 头文件,添加后如图 10-16 所示。
第七步:添加 CppUnit 库文件。 选择菜单“工程”→“添加工程”→“文件”选项。把 CppUnit 相关的 lib 文件和 dll 文件 (cppunitd.lib、cppunitd_dll.lib、testrunnerd.lib)加入到工程中。 第八步:设置头文件和 lib 库文件路径,打开 RTTI 开关,给 dll 库设置环境变量。 单击“工具”下拉菜单,选择“选择”菜单项,在弹出的“选择”对话框中选择“目录”选项 卡,设置 CppUnit 的 include 文件路径和 lib 文件路径,如图 10-17 所示。
单击“工程”下拉菜单,选择“设置”菜单项,在弹出的“工程设置”对话框中选择 C/C++ 选项卡,在“分类”下拉列表中选择 C++ Language 选项,选中“允许时间类型信息(RTTI)”复 选框,如图 10-18 所示。 TestRunnerd.dll 提供了基于 GUI 的测试环境,为了让我们的测试程序能正确调用它,需要把 TestRunnerd.dll 拷贝到工程路径下,或者在操作系统的环境变量 Path 中添如 TestRunnerd.dll 的路径。 第九步:编译执行。 编译连接成功后,运行测试,出现如图 10-19 所示窗口,表示测试用例 Test1 运行成功。