CUnit使用简介
一、介绍
继Junit CppUnit的成功后, c语言环境下也出现了开发源码的白盒测试用例CUnit。CUnit以静态库的形式提供给用户使用,用户编写程序的时候直接链接此静态库就可以了。它提供了一个简单的单元测试框架,并且为常用的数据类型提供了丰富的断言语句支持。
二、结构框架
在CUnit的主页上可以看到对他结构的简单描述
Test Registry
|
——————————
| |
Suite ‘1′ . . . . Suite ‘N’
| |
————— —————
| | | |
Test ‘11′ … Test ‘1M’ Test ‘N1′ … Test ‘NM’
CUnit的测试是单线程启动,只能注册一个测试用例Test Registry,测试用例下可以注册多个测试套件Suite,每个套件下可以注册多个测试函数Test,每个测试函数里又可以写多个断言ASSERT。
三、测试模式
下面是四种测试模式:
1 Automated Output to xml file Non-interactive
2 Basic Flexible programming interface Non-interactive
3 Console Console interface (ansi C) Interactive
4 Curses Graphical interface (Unix) Interact
注意1,2是没有交互功能的,4是Unix下的。
Windows下的Basic模式灵活性比较大一点,比如你可以选择如下运行模式:
CU_BRM_NORMAL /**< 正常模式 - 打印错误和运行总结 [默认] */
CU_BRM_SILENT /**< 安静模式 - 只打印框架错误信息 */
CU_BRM_VERBOSE /**< 冗余模式 - 输出详细的运行结果 */
还可以指定遇见错误时的动作:
CUEA_IGNORE /**< 当出现错误时继续往下运行 */
CUEA_FAIL /**< 当有错误出现时停止(stop) */
CUEA_ABORT /**< 当错误出现时应用程序终止(exit) */
第一种Automated运行以后会自动生成一个xml文件,通过dtd和xsl文件的辅助可以在浏览器中显示出测试结果。
第三种Console个人认为目前的功能还不是很强大,主要功能就是可以分别执行测试套件suite程序,但是操作起来十分的不方便。
四、测试基本流程
使用CUnit进行测试的基本流程如下所示:
1.书写待测试的函数(如果有必要,需要写suite的init/cleanup函数)
2.初始化Test Registry - CU_initialize_registry()
3.把测试套件(Test Suites)加入到Test Registry - CU_add_suite()
4.加入测试用例(Test Case)到测试套件当中 - CU_add_test()
5.使用适当的接口来运行测试测试程序,例如 CU_console_run_tests()
6.清除Test Registry - CU_cleanup_registry()
五、测试框架的安装
没有CUnit源码去http://sourceforge.net/projects/cunit/去下一份,笔者使用的是CUnit-2.1-0,安装十分的方便,Unix下只需要configure, make, make install就行了,Windows下也有相应的VC工程目录,这里就不再獒述了,需要注意的是,源代码里的Example使用了废弃的CUnit函数命名,所以编译的时候需要加一个USE_DEPRECATED_CUNIT_NAMES预定义。
六、具体使用
/* test.c */ int maxi(int i, int j) { return i > j ? i : j; }
/* testcase.c */ #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <CUnit/CUnit.h> /** * 待测试的函数 */ extern int maxi(int i, int j); /** * 测试函数 * 必须满足签名式 void func(void) */ void testIQJ(void) { CU_ASSERT_EQUAL(maxi(1,1),1); CU_ASSERT_EQUAL(maxi(0,-0),0); } void testIGJ(void) { CU_ASSERT_EQUAL(maxi(2,1),2); CU_ASSERT_EQUAL(maxi(0,-1),0); CU_ASSERT_EQUAL(maxi(-1,-2),-1); } void testILJ(void) { CU_ASSERT_EQUAL(maxi(1,2),2); CU_ASSERT_EQUAL(maxi(-1,0),0); CU_ASSERT_EQUAL(maxi(-2,-1),-1); } /** * 测试函数信息的结构体 * 当然也可以使用 CU_add_test() * 注意必须以 CU_TEST_INFO_NULL 结尾 */ CU_TestInfo testcases[] = { {"Testing i equals j:", testIQJ}, {"Testing i greater than j:", testIGJ}, {"Testing i less than j:", testILJ}, CU_TEST_INFO_NULL }; /** * 测试套件初始化函数,对测试函数中的资源进行初始化 * 返回0为成功,如果返回失败则此套件下的测试均不运行 */ int suite_init(void) { return 0; } /** * 测试套件销毁函数,对测试函数中的资源进行销毁 * 返回0为成功,如果返回失败不影响测试,只会报测试套件运行错误 */ int suite_clean(void) { return 0; } /** * 测试套件信息的结构体 * 当然也可以使用 CU_add_suite() * 注意必须以 CU_SUITE_INFO_NULL 结尾 * 如不需要初始化或者最终化函数则可以传NULL */ CU_SuiteInfo suites[] = { {"Testing the function maxi:", suite_init, suite_clean, testcases}, CU_SUITE_INFO_NULL }; /** * 增加到Registry中 */ void AddTests(void) { assert(NULL != CU_get_registry()); assert(!CU_is_test_running()); if(CUE_SUCCESS != CU_register_suites(suites)){ fprintf(stderr, "Register suites failed - %s ", CU_get_error_msg()); exit(EXIT_FAILURE); } }
/* main.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <CUnit/Basic.h> #include <CUnit/Automated.h> #include <CUnit/Console.h> extern void AddTests(void); int main(int argc, char* argv[]) { /* 为Basic模式使用 */ CU_BasicRunMode mode = CU_BRM_VERBOSE; CU_ErrorAction error_action = CUEA_IGNORE; int i; setvbuf(stdout, NULL, _IONBF, 0); for (i=1 ; i<argc ; i++) { if (!strcmp("-i", argv[i])) { error_action = CUEA_IGNORE; } else if (!strcmp("-f", argv[i])) { error_action = CUEA_FAIL; } else if (!strcmp("-A", argv[i])) { error_action = CUEA_ABORT; } else if (!strcmp("-s", argv[i])) { mode = CU_BRM_SILENT; } else if (!strcmp("-n", argv[i])) { mode = CU_BRM_NORMAL; } else if (!strcmp("-v", argv[i])) { mode = CU_BRM_VERBOSE; } else if (!strcmp("-e", argv[i])) { return 0; } else { printf("\nUsage: BasicTest [options]\n\n" "Options: -i ignore framework errors [default].\n" " -f fail on framework error.\n" " -A abort on framework error.\n\n" " -s silent mode - no output to screen.\n" " -n normal mode - standard output to screen.\n" " -v verbose mode - max output to screen [default].\n\n" " -e print expected test results and exit.\n" " -h print this message and exit.\n\n"); return 0; } } /* 初始化registry */ if( CUE_SUCCESS != CU_initialize_registry()) { return CU_get_error(); } else { /* 增加测试套件suite */ AddTests(); /* 用不同模式运行 */ /*CU_basic_set_mode(mode); CU_basic_run_tests();*/ CU_automated_run_tests(); /*CU_console_run_tests();*/ /* 清除registry */ CU_cleanup_registry(); } return 0; }