1.Cunit介绍
CUnit是一个对C语言编写的程序进行单元测试的框架,它作为一个静态链接库被链接到用户的测试代码中,它提供了一种简洁的框架来建立测试架构,并提供丰富的断言来测试通过数据类型。它还提供了许多不同的结构来运行测试用例和报告测试结果。
1.1CUnit的架构
(1)每个测试用例被包装在一个测试包(suite)中
(2)每个测试包(suite)是在有效的测试注册单元(Test Registry)
注册单元下面包含多个测试包,每个测试包可以拥有多个测试用例,至于测试用例,则用来测试模块内部的函数。测试用例函数通过提供的各类输入调用被测试的函数,返回执行结果,然后通过CUnit提供的断言来判断被测试的函数是否正确。
1.2 测试模式
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) Interactive
第一种模式是将结果输出到XML文档中,便于生成报告。第二种模式是每一次运行结束之后在standard output中显示测试结果,不能保留测试结果数据。第三种模式是console方式的,可以人机交互;前两种模式是非交互式的。第四种只在Unix中使用。
1.3 测试的基本流程
1.编写单元测试函数
2.调用函数CU_initialize_registry()初始化测试注册单元(Test Registry)
3.调用函数CU_add_suite() 将测试包(suite)添加到测试注册单元(Test Registry)中
4.调用函数CU_add_test()将测试用例添加到测试包(suite)中
5.用合适的接口来运行测试用例 (对应参数模式)
6.调用函数CU_cleanup_registry清除测试注册单元(Test Registry)
2. CUnit配置
2.1CUnit安装配置
将从网上下载的CUnit-2.1-3安装包解压放到ubuntu中,进入CUnit-2.1-3目录输入./configure进行安装,configure是一个安装脚本。
第二步:使用make进行配置
第三步:使用make install (需要root权限也就是需要加sudo)
第四步:编译 /etc/ld.so.conf文件,在文件加上/usr/local/lib
第五步:使用ldconfig命令
注意:如果配置有问题可以尝试添加sudo权限
2.2 CUnit测试安装是否正确
将 http://cunit.sourceforge.net/example.html 页面的例子复制下来,保存为 cunit.c 文件
编译: gcc -o cunit cunit.c -lcunit
运行:./cunit
3.使用实例
3.1.被测试的模块:
(1) 文件ap_math.c,定义了一个求和函数cal_num。
(2) 头文件ap_math.h,声明了求和函数cal_num。
ap_math.c文件
#include "ap_math.h"
int cal_num(int a, int b)
{
int c;
c = a + b;
return c;
}
ap_math.h文件
int cal_num(int a, int b);
3.2.测试用例和测试包
(1) 文件test_ap_math.c,定义了测试用例。
#include <CUnit/Basic.h>
#include <CUnit/Console.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
#include "ap_math.h"
int init_suite()
{
return 0;
}
int end_suite()
{
return 0;
}
int test_is_euqal(int a, int b, int real)
{
int result;
result = cal_num(a, b);
if (result == real)
{
return 1;
}
return 0;
}
int test_is_not_equal(int a, int b, int real)
{
int result;
result = cal_num(a, b);
if (result != real)
{
return 1;
}
return 0;
}
void test1()
{
int i;
for(i = 0; i < 100000; i++)
CU_ASSERT(test_is_euqal(3+i, 4, 7+i)); //根据返回值
CU_ASSERT(test_is_euqal(20+i, 20+i, 40+2*i));
}
void test2()
{
CU_ASSERT(test_is_not_equal(3, 4 ,10));
}
int test_cal_module()
{
CU_pSuite p_suite = NULL;
p_suite = CU_add_suite("test_suite", init_suite, end_suite);
if (p_suite == NULL)
{
return 1;
}
if(CU_add_test(p_suite, "test1", test1) == NULL
||CU_add_test(p_suite, "test2", test2) ==NULL)
{
return -1;
}
return 0;
}
这二个函数类型驱动的加载和卸载函数
int init_suite()
{
return 0;
}
int end_suite()
{
return 0;
}
test1和test1函数是二个测试样例。分别是test1通过调用CU_ASSERT断言来判断是否通过调用cal_num函数(被测函数)给被测函数传参20,20看其返回值是否能跟预期40相等。test2通过给被测函数传参3,4是否不等于10。
int test_is_euqal(int a, int b, int real)
{
int result;
result = cal_num(a, b);
if (result == real)
{
return 1;
}
return 0;
}
int test_is_not_equal(int a, int b, int real)
{
int result;
result = cal_num(a, b);
if (result != real)
{
return 1;
}
return 0;
}
void test1()
{
CU_ASSERT(test_is_euqal(20, 20, 40));
}
void test2()
{
CU_ASSERT(test_is_not_equal(3, 4 ,10));
}
使用CU_add_suite接口测试包(suite)添加到测试注册单元(Test Registry)中,再使用CU_add_test接口将test1和test2添加到测试包(suite)中。
int test_cal_module()
{
CU_pSuite p_suite = NULL;
p_suite = CU_add_suite("test_suite", init_suite, end_suite);
if (p_suite == NULL)
{
return 1;
}
if(CU_add_test(p_suite, "test1", test1) == NULL
||CU_add_test(p_suite, "test2", test2) ==NULL)
{
return -1;
}
return 0;
}
3.3.单元测试运行入口
test_run.c文件
先使用CU_initialize_registry函数进行初始化,然后添加测试用例,在选择用那种控制模式。然后调用CU_cleanup_registry函数其实就是调用上面的end_suite函数。
#include <stdio.h>
#include <assert.h>
#include "CUnit/Basic.h"
extern int test_cal_module ();
int main(int argc, char const *argv[])
{
if (CU_initialize_registry() != CUE_SUCCESS)
{
return CU_get_error();
}
assert(CU_get_registry() != NULL);
assert(!CU_is_test_running());
if (test_cal_module() != 0)
{
CU_cleanup_registry();
return CU_get_error();
}
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
// CU_console_run_tests();
CU_cleanup_registry();
return 0;
}
3.4编译链接
编译和运行
gcc -o test ap_math.c test_ap_math.c test_run.c -lcunit
./test
运行结果
4.断言和测试模式的使用
4.1断言的使用
Cunit提供一系列的断言来测试逻辑条件,这些断言的成功或者失败的结果都是由CUnit框架进行跟踪,并在单元测结束后可以看到。每个断言测试一个逻辑条件,如果我们选择了”xxx_FATAL"断言,也就是说断言一但失败那个单位测试用例就不会再继续执行了。断言是包含在“CUnit/CUnit.h"这个头文件中。
用于判断表达式是否为真(non-zero)
CU_ASSERT(int expression)
CU_ASSERT_FATAL(int expression)
CU_TEST(int expression)
CU_TEST_FATAL(int expression)
用于判断数值是否为真(non-zero)
CU_ASSERT_TRUE(value)
CU_ASSERT_TRUE_FATAL(value)
判断数据只是为假(zero)
CU_ASSERT_FALSE(value)
CU_ASSERT_FALSE_FATAL(value)
判断是否为等式
CU_ASSERT_EQUAL(actual, expected)
CU_ASSERT_EQUAL_FATAL(actual, expected)
判断是否为不等式
CU_ASSERT_NOT_EQUAL(actual, expected))
CU_ASSERT_NOT_EQUAL_FATAL(actual, expected)
判断指针是否为等式
CU_ASSERT_PTR_EQUAL(actual, expected)
CU_ASSERT_PTR_EQUAL_FATAL(actual, expected)
判断指针是否不是等式
CU_ASSERT_PTR_NOT_EQUAL(actual, expected)
CU_ASSERT_PTR_NOT_EQUAL_FATAL(actual, expected)
判断字符串是否相等
CU_ASSERT_STRING_EQUAL(actual, expected)
CU_ASSERT_STRING_EQUAL_FATAL(actual, expected)
判断字符串是否不同
CU_ASSERT_STRING_NOT_EQUAL(actual, expected)
CU_ASSERT_STRING_NOT_EQUAL_FATAL(actual, expected)
4.2测试模式的使用
这下面是对应于三种模式分别是自动化模式,基础模式,控制模式。
/**** Automated Mode *****************/
CU_set_output_filename("TestMax");
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();
//************************************/
5.CUnit使用总结
如下图所示被测函数由输入一系列参数然后得到结果,跟我们事先设定好的期望值对比,测试是否期望值不符,比如上面一个简单的例子,被测函数是一个二个数的求和函数,咱们向被测函数输入3和4二个求和数,其函数正确执行的话应该是会得到7这个期望值。而7这个期望值balue就是我们事先设定好的。与函数执行完得到的返回值进行比较,通过CUnit框架提供的断言接口来记录这些比较是否有出现异常,如有出现异常会在结果输出中标识出来。