以md5测试为例子,练习了cunit这个单元测试工具。
要写一个测试用例,只需要遵循用例的框架编写就好了。
我们应该要清楚自己编写的函数的输入是什么,输出是什么。然后使用cunit的断言看结果是否符合预期,是的话测试通过,否则说明编码有问题。
就这次将要编写的md5为例,需要测试两个函数,一个是输入字符串,输出计算后的md5值,另一个是输入文件路径,输出文件的md5值。所以用例是否通过的条件就是计算的md5值是否正确。
先来看看main函数
:::c
int main(int argc, const char *argv[])
{
return run_test();
}
没什么特别的,就是运行了run_test
这个函数。
再来看看run_test
:::c
int run_test()
{
if(CU_initialize_registry())
{
exit(EXIT_FAILURE);
}
else
{
AddTests();
/**** Automated Mode *****************
CU_set_output_filename("TestMax");
CU_list_tests_to_file();
CU_automated_run_tests();
//************************************/
/*********basic mode**************/
// CU_basic_set_mode(CU_BRM_VERBOSE);
// CU_basic_run_tests();
/*********console mode**************/
CU_console_run_tests();
CU_cleanup_registry();
return CU_get_error();
}
}
开始变得有趣了,我们看到运行cunit,先要执行CU_initialize_registry()
,成功后运行我们写的AddTests
添加测试用例,接着运行测试模式,这里有三种,我用了第三种控制台模式。最后return退出。
接着来看看我们的AddTests
做了什么工作。
:::c
void AddTests()
{
assert(NULL != CU_get_registry());
assert(!CU_is_test_running());
if(CUE_SUCCESS != CU_register_suites(suites))
{
exit(EXIT_FAILURE);
}
}
原来AddTests
的动作就是注册suites。那么什么是suites?
:::c
CU_TestInfo testcase[] = {
{"test for md5", test_md5_null},
{"test for md5 a", test_md5_a},
{"test for md5 letter", test_md5_letter},
CU_TEST_INFO_NULL
};
CU_TestInfo testcase2[] = {
{"test for md5 file", test_md5_file},
CU_TEST_INFO_NULL
};
int suite_success_init(void)
{
return 0;
}
int suite_success_clean(void)
{
return 0;
}
CU_SuiteInfo suites[] = {
{"test suite 1", suite_success_init, suite_success_clean,testcase},
{"test suite 2", suite_success_init, suite_success_clean,testcase2},
CU_SUITE_INFO_NULL
};
从下往上看,suites 其实就是记录SuiteInfo的结构体,这里有两个suite,分别是suite1和suite2,而suite1中包含三个测试用例,suite2中包含一个。
最终我们就是要编写这些测试用例来完成测试。
例如test_md5_null
,是用来测试null时计算到的md5值是否正确的。
:::c
void test_md5_null(void)
{
char* target;
target = (char* )malloc((MD5_DIGEST_LENGTH * 2 + 1) * sizeof(char));
md5_string("", target);
printf("target is %s \n", target);
CU_ASSERT_STRING_EQUAL(target, "d41d8cd98f00b204e9800998ecf8427e");
free(target);
}
我们知道null的正确md5值是d41d8cd98f00b204e9800998ecf8427e
,计算结果是target,使用CU_ASSERT_STRING_EQUAL
来判断结果是否相等。
流程大致上就这样。写了个简单的Makefile
:::sh
INC = -I/usr/local/include/CUnit
LIB = -L/usr/local/lib/
all:md5c.c md5test.c
gcc -o test $(INC) $(LIB) $^ -lcunit -static
clean:
rm test
开始检测字符串时全军覆没。经检测发现是数据类型用错了,在64位系统下,long int是8个字节,而其要求一个4字节的数据类型。
测试结果如下:
:::sh
Running Suite : test suite 1
Running Test : test for md5input src size 0
d41d8cd98f00b204e9800998ecf8427e
target is d41d8cd98f00b204e9800998ecf8427e
Running Test : test for md5 ainput src a size 1
0cc175b9c0f1b6a831c399e269772661
target is 0cc175b9c0f1b6a831c399e269772661
Running Test : test for md5 letterinput src abcdefghijklmnopqrstuvwxyz size 26
c3fcd3d76192e4007dfb496cca67e13b
target is c3fcd3d76192e4007dfb496cca67e13b
Running Suite : test suite 2
Running Test : test for md5 fileopen file error
Run Summary: Type Total Ran Passed Failed Inactive
suites 2 2 n/a 0 0
tests 4 4 4 0 0
asserts 3 3 3 0 n/a
Elapsed time = 0.000 seconds