单元测试工具 CUnit 简介

1. CUnit简介
1.1 CUnit简要描述
CUnit是一个编写、管理及运行c语言单元测试的系统。它使用一个简单的框架来构建测试结构,并为普通数据结构的测试提供丰富的断言。此外,CUnit为测试的运行和结果查看提供了许多不同的接口,包括自动测试模式和可交互的控制台模式。
其常用的数据类型和函数在以下头文件中声明:
头文件 内容描述
<CUnit/CUnit.h> 包括测试用例中常用的宏定义和框架中其它头文件
<CUnit/CUError.h> 错误处理函数及错误编号
<CUnit/TestDB.h> 测试注册簿、测试包和测试用例的操作及数据类型
<CUnit/TestRun.h> 测试运行及结果检索的操作及数据类型
<CUnit/Automated.h> 输出Xml结果相关的自动模式接口
<CUnit/Basic.h> 非交互模式的基本模式接口
<CUnit/Console.h> 交互模式的接口


1.2 测试框架结构
CUnit核心框架为测试注册簿、测试包和测试用例的管理提供了基本支持,它提供的接口可以使用户和测试框架交互,方便测试的运行和测试结果的查看。CUnit被组织成一个常见的单元测试框架,其结构如下:


                      Test Registry
                            |
             ------------------------------
             |                            |
          Suite '1'      . . . .       Suite 'N'
             |                            |
       ---------------             ---------------
       |             |             |             |
    Test '11' ... Test '1M'     Test 'N1' ... Test 'NM'


测试用例被打包成测试包,并被注册到当前活动的测试注册簿中。测试包的装载和卸载函数在测试执行前后被自动调用。所有的测试包和测试用例可以一键运行,也可以选择相应的测试包或测试用例来执行测试。


1.3 基本使用方法
使用CUnit框架的常用流程如下:
编写测试用例,如果有必要须对测试包进行初始化或者清理
初始化测试注册簿 CU_initialize_registry()
向注册簿中注册测试包 CU_add_suite()
向测试包中添加测试用例 CU_add_test()
使用合适的测试模式执行测试 CU_automated(basic/console/curses)_run_tests()
清理测试注册簿 CU_cleanup_registry()
1.4 Linux下CUnit的安装


The usual sequence of steps should succeed in building and installing CUnit:
aclocal  (if necessary)
autoconf (if necessary)
automake (if necessary)
chmod u+x configure (if necessary)
./configure --prefix <Your choice of directory for installation>
make
make install


What's installed:
libcunit.a (Library file)
CUnit Header files
DTD and XSL files supporting xml output files in share directory
Man Pages in relevant man directories under the installation path.
HTML users guide in the doc subdirectory of the installation path.
Example & test programs in the share subdirectory of the install path.


2. 编写CUnit测试用例
2.1 测试用例函数的命名
CUnit中对于测试函数的定义没有严格的规范,一个常用的示例如下:
int maxi(int i1, int i2)
{
return (i1 > i2) ? i1 : i2;
}


void test_maxi(void)
{
CU_ASSERT(maxi(0,2) == 2);
CU_ASSERT(maxi(0,-2) == 0);
CU_ASSERT(maxi(2,2) == 2);
}
2.2 CUnit中的断言
CUnit为逻辑条件测试提供了一系列的断言。测试框架会跟踪这些断言的通过或失败,当测试执行完成时便可看到结果。 
每一个断言测试一个逻辑条件,条件的值为CU_FALSE表示断言失败。对于测试失败,测试将会继续执行,除非用户选择“xxx_FATAL”类型的断言,这种情况下该测试函数将会失败并立即返回。FATAL类型的断言应该和警告一块使用!一旦FATAL类型的断言导致测试失败,测试函数将没有机会做清理工作,普通的清理函数不会起任何作用。
另外一些特殊的断言被注册为“pass”或“fail”,它们不是用来做逻辑测试,而是用来测试流程控制或者其他条件测试的。例如:
void test_longjmp(void)
{
jmp_buf buf;
int i;


i = setjmp(buf);
if (i == 0) {
run_other_func();
CU_PASS("run_other_func() succeeded.");
}
else
CU_FAIL("run_other_func() issued longjmp.");
}
所有的断言被定义在<CUnit/CUnit.h>
3. 测试注册簿
3.1 常用相关函数
#include  <CUnit/TestDB.h> 
typedef struct CU_TestRegistry
typedef CU_TestRegistry* CU_pTestRegistry
CU_ErrorCode CU_initialize_registry(void)
void CU_cleanup_registry(void)
CU_BOOL CU_registry_initialized(void)
CU_pTestRegistry CU_get_registry(void)
CU_pTestRegistry CU_set_registry(CU_pTestRegistry pTestRegistry)
CU_pTestRegistry CU_create_new_registry(void)
void CU_destroy_existing_registry(CU_pTestRegistry* ppRegistry)
3.2 注册簿内部结构体
测试注册簿是测试包和相关测试用例的仓库。当用户添加测试包或测试用例时,CUnit维护当前活动的测试注册簿的状态更新,当用户选择运行所有测试用例时,当前活动的注册簿中所有的测试包均被执行。
    测试注册簿结构在<CUnit_TestDB.h>中定义,它包括所有测试包的数量、所有测试用例的数量以及一个指向该注册簿中测试包链表的指针:
typedef struct CU_TestRegistry
{
unsigned int uiNumberOfSuites;
unsigned int uiNumberOfTests;
CU_pSuite    pSuite;
} CU_TestRegistry;
typedef CU_TestRegistry* CU_pTestRegistry;
用户通常只需在使用前初始化测试注册簿,之后做清除工作即可。此外CUnit还提供了一些必要的注册簿操作函数。
3.3 注册簿初始化
当前活动状态的注册簿在使用前必须初始化,用户在调用其它函数之前,须调用初始化函数。初始化失败将导致测试程序崩溃。如果多次调用初始化函数,在创建新的注册簿之前,所有存在的注册簿都将被清空。在测试执行期间,初始化函数不应该被调用!
CU_ErrorCode CU_initialize_registry(void)  //return CUE_SUCCESS or CUE_NOMEMORY
用户可以调用如下函数判断注册簿是否已经初始化:
CU_BOOL CU_registry_initialized(void)
3.4 注册簿的清理
当测试完成后,用户应该调用注册簿清理函数 CU_cleanup_registry() 以释放测试框架所占用的内存。该清理函数应该最后被调用,忘记调用清理函数将导致内存泄露。注册簿被清理之后,所有与该注册簿相关的测试包、测试用例都不能被引用。测试执行期间不应该调用该函数。清理函数只对当前活动的注册簿起作用,用户其它注册簿的清理工作可以通过显式的调用CU_destroy_existing_registry(),或者隐式的调用CU_set_registry()和CU_cleanup_registry()去清理。
3.5 与注册簿相关的其它函数
CU_pTestRegistry CU_get_registry(void)
CU_pTestRegistry CU_set_registry(CU_pTestRegistry pTestRegistry)
CU_pTestRegistry CU_create_new_registry(void)
void CU_destroy_existing_registry(CU_pTestRegistry* ppRegistry)
4. 测试包及测试用例的管理
4.1 相关函数及结构
#include <CUnit/TestDB.h>
typedef struct CU_Suite
typedef CU_Suite* CU_pSuite


typedef struct CU_Test
typedef CU_Test* CU_pTest


typedef void (*CU_TestFunc)(void)
typedef int (*CU_InitializeFunc)(void)
typedef int (*CU_CleanupFunc)(void)


CU_pSuite CU_add_suite(const char* strName,CU_InitializeFunc pInit,CU_CleanupFunc pClean);
CU_pTest   CU_add_test(CU_pSuite pSuite,const char* strName,CU_TestFunc pTestFunc);


typedef struct CU_TestInfo
typedef struct CU_SuiteInfo


CU_ErrorCode CU_register_suites(CU_SuiteInfo suite_info[]);
CU_ErrorCode CU_register_nsuites(int suite_count, ...);


CU_ErrorCode CU_set_suite_active(CU_pSuite pSuite, CU_BOOL fNewActive)
CU_ErrorCode CU_set_test_active(CU_pTest, CU_BOOL fNewActive)


CU_ErrorCode CU_set_suite_name(CU_pSuite pSuite, const char *strNewName)
CU_ErrorCode CU_set_suite_initfunc(CU_pSuite pSuite, CU_InitializeFunc pNewInit)
CU_ErrorCode CU_set_suite_cleanupfunc(CU_pSuite pSuite, CU_CleanupFunc pNewClean)


CU_ErrorCode CU_set_test_name(CU_pTest pTest, const char *strNewName)
CU_ErrorCode CU_set_test_func(CU_pTest pTest, CU_TestFunc pNewFunc)


CU_pSuite CU_get_suite(const char* strName)
CU_pSuite CU_get_suite_at_pos(unsigned int pos)
unsigned int CU_get_suite_pos(CU_pSuite pSuite)
unsigned int CU_get_suite_pos_by_name(const char* strName)


CU_pTest CU_get_test(CU_pSuite pSuite, const char *strName)
CU_pTest CU_get_test_at_pos(CU_pSuite pSuite, unsigned int pos)
unsigned int CU_get_test_pos(CU_pSuite pSuite, CU_pTest pTest)
unsigned int CU_get_test_pos_by_name(CU_pSuite pSuite, const char *strName)
4.2 注册测试包
CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)
创建一个测试包,该测试包拥有自己特定的名字、初始化函数及清理函数。该测试包被注册到一个测试注册簿,该注册簿在添加任意测试包之前须初始化。当前版本不支持独立于注册簿之外的测试包的创建,该函数不应该在测试执行期间被调用。
在注册簿中,推荐每个测试包有唯一的名字,这样可以通过名字查找测试包。在上述函数中,测试包的初始化函数和清理函数是可选的,如果不需要这些函数可以传参数NULL。
该函数返回值分为五种:
CUE_SUCCESS suite creation was successful.
CUE_NOREGISTRY Error the registry has not been initialized.
CUE_NO_SUITENAME ErrorstrName was 
NULL.CUE_DUP_SUITE Warning the suite's name was not unique.
CUE_NOMEMORY Error memory allocation failed.
4.3 添加测试用例到测试包
CU_pTest CU_add_test(CU_pSuite pSuite, const char* strName, CU_TestFunc pTestFunc)
创建一个测试用例,该测试包拥有自己特定的名字、初始化函数及清理函数。该测试用例被打包到一个测试包,当前版本不支持独立于测试包之外的创建,该函数不应该在测试执行期间被调用。
在单个测试包中,推荐每个测试用例有唯一的名字,这样可以通过名字查找测试用例。参数接受一个测试函数的函数指针,不可以为空,当执行测试时,该函数将被调用。测试函数没有参数也没有返回值。
该函数返回值分为7种:
CUE_SUCCESS suite creation was successful.
CUE_NOREGISTRY Error: the registry has not been initialized.
CUE_NOSUITE Error: the specified suite was NULL or invalid.
CUE_NO_TESTNAME Error: strName was NULL.
CUE_NO_TEST Error: pTestFunc was NULL or invalid.
CUE_DUP_TEST Warning: the test's name was not unique.
CUE_NOMEMORY Error: memory allocation failed.
4.4 测试包及测试用例管理的快捷方法
CUnit定义了许多类似如下的宏:
#define CU_ADD_TEST(suite, test) (CU_add_test(suite, #test, (CU_TestFunc)test))
这些宏可以针对测试函数名字,自动生成拥有惟一名字的测试用例,并将该测试用例添加到指定的测试包,用户应该验证返回值以保证正常添加。
CU_ErrorCode CU_register_suites(CU_SuiteInfo suite_info[])
CU_ErrorCode CU_register_nsuites(int suite_count, ...)
对于拥有很多测试包和测试用例的大型测试结构,管理测试包和测试用例的关联和注册是相当乏味和易出错的。CUnit提供了一个特殊的注册系统来帮助用户管理测试包和测试用例。这个系统将测试包的注册和测试用例的关联集中起来,以缩减用户的代码量。
CU_TestInfo实例可以将许多测试用例集中放到一个数组,以便于关联到一个测试包。每个数组元素包括一个惟一的名字和测试函数。该数组必须以CU_TEST_INFO_NULL结尾。
CU_TestInfo test_array1[] = {
{ "testname1", test_func1 },
{ "testname2", test_func2 },
{ "testname3", test_func3 },
CU_TEST_INFO_NULL,
};
同样的,CU_SuiteInfo也提供类似的封装功能,它将测试包名字、测试包初始化函数、清理函数和其关联的测试用例封装起来。
CU_SuiteInfo suites[] = {
{ "suitename1", suite1_init-func, suite1_cleanup_func, test_array1 },
{ "suitename2", suite2_init-func, suite2_cleanup_func, test_array2 },
CU_SUITE_INFO_NULL,
};
这样,我们将整个注册流程简化为:
CU_ErrorCode error = CU_register_suites(suites);
或者
CU_ErrorCode error = CU_register_nsuites(2, suites1, suites2);
这些函数的返回值和包注册函数、测试用例关联函数相同
4.5 设置当前活动测试包和测试用例
CU_ErrorCode CU_set_suite_active(CU_pSuite pSuite, CU_BOOL fNewActive)
CU_ErrorCode CU_set_test_active(CU_pTest pTest, CU_BOOL fNewActive)
这些函数被用来测试包测试用例为当前活动包和当前活动测试用例,一个测试包或者测试用例在执行测试时不会被执行,除非用户将它设置为是当前活动的。所有的测试包和测试用例在创建时被默认设置为活动的。当前活动状态可以通过pSuite->fActive或pTest->fActive获取。这样,客户端就有能力动态地选择测试用例去执行测试。如果参数对应的包或者用例不存在则返回CUE_NOSUIT或CUI_NOTEST。
4.6 修改测试包和测试用例的属性
CU_ErrorCode CU_set_suite_name(CU_pSuite pSuite, const char *strNewName)
CU_ErrorCode CU_set_test_name(CU_pTest pTest, const char *strNewName)
CU_ErrorCode CU_set_suite_initfunc(CU_pSuite pSuite, CU_InitializeFunc pNewInit)
CU_ErrorCode CU_set_suite_cleanupfunc(CU_pSuite pSuite, CU_CleanupFunc pNewClean)
CU_ErrorCode CU_set_test_func(CU_pTest pTest, CU_TestFunc pNewFunc)
4.7 测试包和测试用例的查询
大多数情况下,客户端可以通过注册测试包和关联测试用例获取它们的引用。有时候客户端可能需要有能力去检索某个测试包或测试用例的引用。CUnit提供给客户端获取某个测试包或测试用例信息的能力。
CU_pSuite CU_get_suite(const char* strName)
CU_pSuite CU_get_suite_at_pos(unsigned int pos)
unsigned int CU_get_suite_pos(CU_pSuite pSuite)
unsigned int CU_get_suite_pos_by_name(const char* strName)
这些函数使用户查询注册到当前活动注册簿中的测试包。可以通过传入名字、位置参数来获取测试包,如果该测试包不存在,则返回NULL。位置参数从1开始到注册簿中的测试包数。按名字查询的方式只返回测试包链表中的第一个测试包。如果注册簿没有初始化则错误码为CUE_NOREGISTRY,相应的,如果按名字查找的包不存在,错误码为CUE_NO_SUITENAME且返回NULL。
CU_pTest CU_get_test(CU_pSuite pSuite, const char *strName)
CU_pTest CU_get_test_at_pos(CU_pSuite pSuite, unsigned int pos)
unsigned int CU_get_test_pos(CU_pSuite pSuite, CU_pTest pTest)
unsigned int CU_get_test_pos_by_name(CU_pSuite pSuite, const char *strName)
如上函数和测试包查询类似。
5. 运行测试
5.1 常用相关函数
#include <CUnit/Automated.h>
void         CU_automated_run_tests(void)
CU_ErrorCode CU_list_tests_to_file(void)
void         CU_set_output_filename(const char* szFilenameRoot)


#include <CUnit/Basic.h>
typedef enum     CU_BasicRunMode
CU_ErrorCode     CU_basic_run_tests(void)
CU_ErrorCode     CU_basic_run_suite(CU_pSuite pSuite)
CU_ErrorCode     CU_basic_run_test(CU_pSuite pSuite, CU_pTest pTest)
void             CU_basic_set_mode(CU_BasicRunMode mode)
CU_BasicRunMode CU_basic_get_mode(void)
void             CU_basic_show_failures(CU_pFailureRecord pFailure)


#include <CUnit/Console.h>
void CU_console_run_tests(void)


#include <CUnit/CUCurses.h>
void CU_curses_run_tests(void)


#include <CUnit/TestRun.h> 
unsigned int CU_get_number_of_suites_run(void)
unsigned int CU_get_number_of_suites_failed(void)
unsigned int CU_get_number_of_tests_run(void)
unsigned int CU_get_number_of_tests_failed(void)
unsigned int CU_get_number_of_asserts(void)
unsigned int CU_get_number_of_successes(void)
unsigned int CU_get_number_of_failures(void)


typedef struct CU_RunSummary
typedef CU_Runsummary* CU_pRunSummary
const CU_pRunSummary CU_get_run_summary(void)


typedef struct CU_FailureRecord
typedef CU_FailureRecord*   CU_pFailureRecord
const CU_pFailureRecord CU_get_failure_list(void)
unsigned int CU_get_number_of_failure_records(void)


void CU_set_fail_on_inactive(CU_BOOL new_inactive)
CU_BOOL CU_get_fail_on_inactive(void)
5.2 自动模式
CUnit支持运行注册簿中所有的测试用例,它同时支持单独运行某个测试包或测试用例。 CUnit框架会在每个测试运行期间跟踪测试包、用例、断言以及断言通过和失败的数量。需要注意的是,每次测试初始化(即便是初始化失败)前次的测试结果都会被清空。,如果客户端想排除某些用例以做某个特殊测试,单个测试包或测试用例可以被设置为非活动。
自动模式接口提供非交互模式测试,用户初始化测试并运行,结果被导出到一个XML文件,所有的测试注册簿和测试包均可以被导出到XML文件。自动模式接口包括如下函数:
void CU_automated_run_tests(void) 该函数运行注册簿中所有活动的的测试包,测试结果被输出到一个名字为ROOT-Results的XML文件。ROOT可以通过 CU_set_output_filename()设置,否则使用默认文件名 CUnitAutomated-Results.xml。需要指出的是,如果不设置一个独特的名字,测试结果会被覆盖。
CU_ErrorCode CU_list_tests_to_file(void) 该函数在文件中列出所有注册的测试包及相关联的测试用例。列表文件名为ROOT-Listing.XML。名字ROOT可以通过 CU_set_output_filename()设置,否则默认文件名CUnitAutomated便被启用,同样的,如果不区分名字,该列表文件将会被覆盖。需要指出的是,如果用户需要一个列表文件,他必须显示地去调用该接口函数。
void CU_set_output_filename(const char* szFilenameRoot) 这个函数用于设置输出结果或列表文件的文件名,该参数后面会相应的追加-Results.xml或-Listing.xml。
5.3 基本模式
基本模式接口也是非交互的,其结果被显示到标准输出。这种接口支持运行单独的测试包或测试用例,并且允许用户代码在测试运行期间控制输出显示的类型。它对用户提供了最灵活的访问方式。
CU_ErrorCode CU_basic_run_tests(void) 该函数执行注册簿中所有活动状态的测试包,其输出类型取决于当前运行模式,运行模式可以通过 CU_basic_set_mode()设置。
CU_ErrorCode CU_basic_run_suite(CU_pSuite pSuite) 该函数运行单个指定的测试包,如果该测试包为NULL或为非活动的,将返回相应的错误码,其输出类型取决于当前运行模式,运行模式可以通过 CU_basic_set_mode()设置。
void CU_basic_set_mode(CU_BasicRunMode mode) 该函数用于设置基本运行模式,可选模式为:
CU_BRM_NORMAL 结果会输出基本信息,包括失败以及测试运行的总体状况
CU_BRM_SILENT 只会输出错误信息
CU_BRM_VERBOSE 输出测试运行的详细信息
CU_BasicRunMode CU_basic_get_mode(void) 用户获取当前基本运行模式。
void CU_basic_show_failures(CU_pFailureRecord pFailure) 输出所有错误的概要到标准输出,与当前基本运行模式无关
5.4 控制台交互模式
    控制台模式是可交互的。用户可以交互地控制测试的运行。包括选择、运行已注册的测试包和测试用例、查看测试结果等。使用 void CU_curses_run_tests(void) 开启控制台模式
5.5 运行时行为修改
下面函数可以允许用户在测试运行期间修改测试框架的行为:
void CU_set_fail_on_inactive(CU_BOOL new_inactive)
CU_BOOL CU_get_fail_on_inactive(void)
默认的运行时行为,将非活动状态的测试包和测试用例当做测试失败输出。如果用户打算将非活动状态的测试包和测试用例忽略,便可以使用该函数修改。CU_FALSE指示测试框架会忽略非活动状态的实体,CU_TURE将会把它们当做测试失败。
5.6 获取测试结果
用户代码可能需要直接访问测试结果,测试结果包括多种运行数量和包括失败详细信息的错误记录表。需要指出的是,当用户运行新的测试、注册簿初始化或清空时,测试结果会被覆盖。可访问测试结果的接口如下:
unsigned int CU_get_number_of_suites_run(void)
unsigned int CU_get_number_of_suites_failed(void)
unsigned int CU_get_number_of_tests_run(void)
unsigned int CU_get_number_of_tests_failed(void)
unsigned int CU_get_number_of_asserts(void)
unsigned int CU_get_number_of_successes(void)
unsigned int CU_get_number_of_failures(void)
这些函数会报告最后一次测试结果中通过和失败的测试包、测试用例和断言的数量。如果测试包在初始化或清理时返回非零值或其为非活动状态,将会被认为测试失败。如果测试用例中任意一个断言失败或起初在非活动状态,该测试用例会被认定为测试失败。最后3个函数涉及到单独的断言,非活动状态的测试包和测试用例不会被统计入内。测试包或测试用例没有被报告为已经运行,它们依然被当做失败处理
const CU_pRunSummary CU_get_run_summary(void) 检索所有测试结果的统计数字。返回值指向一个包括各种统计数字的结构体:
typedef struct CU_RunSummary
{
unsigned int nSuitesRun;
unsigned int nSuitesFailed;
unsigned int nTestsRun;
unsigned int nTestsFailed;
unsigned int nAsserts;
unsigned int nAssertsFailed;
unsigned int nFailureRecords;
} CU_RunSummary;
typedef CU_Runsummary* CU_pRunSummary;
该返回值由框架统一管理,用户不能释放或修改。需要注意的是,如果另一个测试被初始化,该指针可能为无效指针。
const CU_pFailureRecord CU_get_failure_list(void) 检索最后一次测试结果的错误记录链表,如果没有错误该值为NULL。该结构体定义如下:
typedef struct CU_FailureRecord
{
unsigned int  uiLineNumber;
char*         strFileName;
char*         strCondition;
CU_pTest      pTest;
CU_pSuite     pSuite;
struct CU_FailureRecord* pNext;
struct CU_FailureRecord* pPrev;
} CU_FailureRecord;
typedef CU_FailureRecord*  CU_pFailureRecord;
同样的,该指针由测试框架统一管理。
unsigned int CU_get_number_of_failure_records(void) 获取CU_get_failure_list()返回链表中CU_FailureRecord的数量。需要注意的是,该值可以比断言失败数量大,因为初始化或清理失败的测试包被包括在内。


6. 错误处理
6.1 常用相关函数
#include <CUnit/CUError.h>
typedef enum CU_ErrorCode
CU_ErrorCode   CU_get_error(void);
const char*     CU_get_error_msg(void);


typedef enum CU_ErrorAction
void           CU_set_error_action(CU_ErrorAction action);
CU_ErrorAction CU_get_error_action(void);
6.2 错误处理
在CUnit中,多数函数通过设置错误码来指示错误状态。一些函数直接返回错误码,另外一些只设置错误码并返回其他的值。CUnit提供下面两个函数用以检查错误状态:
CU_ErrorCode CU_get_error(void)
const char* CU_get_error_msg(void)
第一个函数返回错误代码,第二个函数返回一个描述错误状态的字符串信息。错误码被定义在<CUnit/CUError.h>,定义了如下:
CUE_SUCCESS No error condition.
CUE_NOMEMORY Memory allocation failed.
CUE_NOREGISTRY Test registry not initialized.
CUE_REGISTRY_EXISTS Attempt to CU_set_registry() without CU_cleanup_registry().
CUE_NOSUITE A required CU_pSuite pointer was NULL.
CUE_NO_SUITENAME Required CU_Suite name not provided.
CUE_SINIT_FAILED Suite initialization failed.
CUE_SCLEAN_FAILED Suite cleanup failed.
CUE_DUP_SUITE Duplicate suite name not allowed.
CUE_SUITE_INACTIVE A test run was requested for an inactive suite.
CUE_NOTEST A required CU_pTest of CU_TestFunc pointer was NULL.
CUE_NO_TESTNAME Required CU_Test name not provided.
CUE_DUP_TEST Duplicate test case name not allowed.
CUE_TEST_NOT_IN_SUITE Test is not registered in the specified suite.
CUE_TEST_INACTIVE A test run was requested for an inactive test.
CUE_FOPEN_FAILED An error occurred opening a file.
CUE_FCLOSE_FAILED An error occurred closing a file.
CUE_BAD_FILENAME A bad filename was requested (NULL, empty, nonexistent, etc.).
CUE_WRITE_ERROR An error occurred during a write to a file
6.3 框架错误的行为
当错误发生时,默认的行为是设置错误码并继续执行。断言失败并不认为是错误。错误包括测试包初始化或清理失败、显示地执行非活动状态的测试包或测试用例等。用户有可能倾向于当框架错误发生时停止测试,CUnit提供下面函数设置:
void CU_set_error_action(CU_ErrorAction action)
CU_ErrorAction CU_get_error_action(void)
错误行为码定义如下:
CUEA_IGNORE Run should be continued when an error condition occurs (default)
CUEA_FAIL Run should be stopped when an error condition occurs
CUEA_ABORT The application should exit() when an error conditions occurs
7. 示例
7.1 待测试模块代码
// module.h
#ifndef _MODULE_H_
#define _MODULE_H_
 
int add(int, int);
int sub(int, int);


#endif


// module.c
#include "module.h"


int add(int a, int b)
{
return a+b;
}


int sub(int a, int b)
{
return a-b;
}
7.2 测试用例及其运行代码
// TestRun.c
#include <CUnit/CUnit.h>
#include <CUnit/Basic.h>
#include <CUnit/Console.h>
#include <CUnit/CUCurses.h>


#include "module.h"
 
void test_add1(void){
CU_ASSERT_EQUAL(add(1,2),3);
}
void test_add2(void){
CU_ASSERT_NOT_EQUAL(add(1,2),4);
}


void test_sub1(void){
CU_ASSERT_EQUAL(sub(1,2),-1);
}
void test_sub2(void){
CU_ASSERT_NOT_EQUAL(sub(1,2),0);
}


CU_TestInfo testcase1[] = {
{"test_for_add1:",test_add1},
{"test_for_add2:",test_add2},
CU_TEST_INFO_NULL
};
 
CU_TestInfo testcase2[] = {
{"test_for_sub1:",test_sub1},
{"test_for_sub2:",test_sub2},
CU_TEST_INFO_NULL
};


int suite_init(void){
return 0;
}
 
int suite_cleanup(void){
return 0;
}


CU_SuiteInfo suites[] = {
{"testSuite1",suite_init,suite_cleanup,testcase1},
{"testsuite2",suite_init,suite_cleanup,testcase2},
CU_SUITE_INFO_NULL
};


int main(int argc, char * argv[])
{
if(CU_initialize_registry()){
fprintf(stderr, " Initialization of Test Registry failed. ");
return CU_get_error();
}else{
if(CUE_SUCCESS != CU_register_suites(suites))
return CU_get_error();

//**** Automated Mode *****************
CU_set_output_filename("ModuleTest");
CU_list_tests_to_file();
CU_automated_run_tests();
//************************************/

/***** Basice Mode *******************
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
//************************************/

/*****Console Mode ********************
CU_console_run_tests();
//************************************/

/*****Curse Mode ********************
CU_curses_run_tests();
//*********************************/

CU_cleanup_registry();
return CU_get_error();
}
}


// Makefile
INC=-I/local/local/include
LIB=-L/local/local/lib


all: module.c TestRun.c
gcc $^ -o TestRun $(INC) $(LIB) -lcunit -lcurses -static
clean:
rm TestRun
7.3 自动模式下的测试结果

单元测试工具 CUnit 简介_第1张图片

你可能感兴趣的:(单元测试,cunit)