1. Cmockery简介:
Cmockery是Google发布的用于C单元测试的一个轻量级框架,该框架有以下几个特点:
- 免费且开源,google提供技术支持;
- 轻量级的框架,测试快速简单;
- 避免使用复杂的编译器特性,对老版本的编译器的兼容性好;
- 不强制要求待测代码必须依赖C99标准,对许多嵌入式系统的开发很有用;
2. Linux下编译:
cd 到Cmockery目录下,执行下面命令:
- sudo ./configure
- sudo make
- sudo make install
库文件安装到:/usr/local/lib
头文件安装到:/usr/local/include/google
此时还需要加载一下Cmockery库:
cd /usr/local/lib
执行命令:sudo ldconfig
项目编译前,有下述文件:
项目编译完,生成了项目中供学习的多个可执行文件:
可在目录下直接运行使用
3. Cmockery的测试实例学习:
下面的内容主要根据Cmockery的手册来展开:
动机
现今的许多C开源测试框架相当复杂,且对于最新的编译器技术有所依赖,使得这些测试框架的使用有一定的局限性。
Cmockery只需要待测试程序与标准C链接,最大限度地减少与标准库文件的冲突,而且,Cmockery尽量避免使用编译器中新的特性,具有更好的兼容性。
概述
Cmockery的测试和Cmockery库、标准C库、待测模块链接在一起,最终被编译成一个可独立运行的程序。测试过程中,待测模块的任何外部信息都应被模拟,即使用测试用例中定义的函数返回值来替换。即使待测代码在实际运行环境和测试环境的运行存在差异,仍可视为有效的测试。因为Cmockery的测试目的在于大吗模块在功能层面上的逻辑测试,不必要求所有的行为都和目标环境一致。
测试执行
Cmockery单元测试用例是签名为void function(void **state)的函数 .
Cmockery 测试程序将(多个)测试用例的函数指针初始化到一个表中,使用unit_test*() 宏. 这个表会传给 run_tests() 宏来执行测试用例。
run_tests() 将适当的异常/信号句柄,以及其他数据结构的指针装入到测试函数。
当单元测试结束时,run_tests() 会显示出各种定义的测试是否成功。
run_test.c文件如下:
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmockery.h>
// A test case that does nothing and succeeds.
void null_test_success(void **state) {//签名为(void** state)的函数作为单元测试用例)
}
int main(int argc, char* argv[]) {
const UnitTest tests[] = { //多个测试用例的函数指针初始化UnitTest的数组中
unit_test(null_test_success),
};
return run_tests(tests); //将初始化的表传递给run_tests函数来执行测试用例,返回测试用例的结果
}
异常处理
测试函数被run_tests() 执行之前,断言/信号句柄会被一个句柄重载,它可以在异常发生时,显示错误并退出测试函数。 如果一个异常发生在测试函数的外部,例如Cmockery本身,程序将终止执行并返回错误码。
出错处理
当测试函数执行run_tests() 时,如果出现错误,当前的测试函数将中断,测试程序继续执行下一测试函数。
测试失败的通过CMockery函数fail() 给出最终的标志。导致Cmockery库测试失败的事件如下:
断言
运行时的断言宏和C标准库的assert() 相似,需要在待测模块中使用Cmockery的mock_assert() 函数重定义。 通常mock_assert() 表示 测试的失败 . 如果一个函数被expect_assert_failure() 宏调用, 那么在这个函数中就要调用mock_assert() ,测试将进行。若没有调用mock_assert() ,表示这个函数测试失败。
mock_module的使用
asset_module.c文件:
#include <assert.h>
// If unit testing is enabled override assert with mock_assert().
#if UNIT_TESTING
extern void mock_assert(const int result, const char* const expression,
const char * const file, const int line);
#undef assert
#define assert(expression) \
mock_assert((int)(expression), #expression, __FILE__, __LINE__);
#endif // UNIT_TESTING
void increment_value(int * const value) {
assert(value);
(*value) ++;
}
void decrement_value(int * const value) {
if (value) {