C单元测试框架——CMockery (3)中文手册

Cmockery 单元测试框架

翻译的匆忙,没有校验,纰漏之处感谢请指正。转载请注明来自:see-see ,版权归原文 所有。

Cmockery 是一个轻量级的库,作者用它来做C单元测试。

动机

如今已经有很多的C单元测试框架可用,但大多数框架相当复杂,并且对最新的编译器技术有所依赖。有些开发会使用老版本的编译器, 这样就很难使用那些测试框架。另外,许多测试框架会假设待测代码(程序或模块)执行的平台是同一个。正因为这种假设,很多测试框架需要在待测模块中引入C标准库的头文件,这不符合惯例,或者在待测模块中实现一个不完全的C库。

Cmockery 只需要测试程序与标准C库链接,这能最大限度地减少与标准库头文件的冲突。此外, Cmockery尽量避免使用编译器中比较新的一些特性。

因此,Cmockery就成了一个可用于测试各种不同的代码轻量级的库。如果开发者只是想简单地测试一个程序,并且可以使用最新的编译器,其他单元测试框架也是可取的。

概述

Cmockery 的测试与Cmockery库,标准C库,待测模块链接在一起,最总被编译成一个可以独立运行的程序。在测试过程中,待测模块的任何外部信息都应被模拟,即用测试用例中定义的函数返回值来替换。即使会出现待测代码在实际运行环境和测试环境运行时有差异,仍可视为有效。因为它的目的在于代码模块在功能面上的逻辑测试,不必要求所有的行为都和目标环境一致。

如果不做一些修改,无法将一个模块编译成可执行程序。因此 UNIT_TESTING 预定义应当定义在执行Cmockery单元测试的应用程序中, 编译待测代码时,可用条件编译决定是否参与单元测试。

执行测试

Cmockery单元测试用例就是函数,签名为void function(void **state) . Cmockery 测试程序将(多个)测试用例的函数指针初始化到一个表中,使用unit_test*() 宏. 这个表会传给 run_tests() 宏来执行测试用例。 run_tests() 将适当的异常/信号句柄,以及其他数据结构的指针装入到测试函数。当单元测试结束时, run_tests() 会显示出各种定义的测试是否成功。

run_tests()的使用方法

run_tests.c ------------------------------------------------------------------------------- 

 

 

 

异常处理

在测试函数被run_tests() 执行之前,断言/信号句柄会被一个句柄重载,它可以在异常发生时,显示错误并退出测试函数。 如果一个异常发生在测试函数的外部,例如Cmockery本身,程序将终止执行并返回错误码。

出错处理

当测试函数执行run_tests() 时,如果错误出现了,当前的测试函数将中断,测试程序继续执行下一测试函数。测试失败的通过CMockery函数fail() 给出最终的标志。导致Cmockery库测试失败的事件如下:

 

断言

运行时的断言宏和C标准库的assert() 相似,需要在待测模块中使用Cmockery的mock_assert() 函数重定义。 通常mock_assert() 表示 测试的失败 . 如果一个函数被expect_assert_failure() 宏调用, 那么在这个函数中就要调用mock_assert() ,测试将进行。若没有调用mock_assert() ,表示次函数测试失败。

mock_assert()的使用

assert_module.c -------------------------------------------------------------------------------

 

 

 

 

assert_module_test.c -------------------------------------------------------------------------------

 

 

 

断言宏

Cmockery提供了一系列的断言宏,在测试程序的使用方法和C标准中的用法一致。 当断言错误发生时,Cmockery的断言宏会将这个这个错误输出到标准错误流,并把这个测试标记为失败。 由于标准C库中assert()的是限制,Cmockery的assert_true() 和 assert_false() 宏只能显示导致断言失败的表达式。Cmockery中和具体类型相关的断言宏, assert_{类型}_equal() and assert_{类型}_not_equal(), 显示那些导致断言失败的数据, 这样可以增加数据的可视化,辅助调试那些出错的测试用例。

assert_{类型}_equal()宏的使用

assert_macro.c -------------------------------------------------------------------------------

 

 

 

 

assert_macro_test.c ----------------------------------------------------------------------------

 

 

 

 

动态内存分配

为了能用Cmockery测试待测模块中的内存泄漏,缓存溢出和underflows问题,应该将对malloc()calloc()free() 的调用分别替换成test_malloc()test_calloc()test_free() 。每次释放块内存是使用test_free() ,如果一个内存块被 标记为测试失败 ,它将检测内存崩溃。所有块的内存分配使用 test_*() 函数,Cmockery库将跟踪它们。当测试完成时,如果有任何分配的块没有被释放(内存泄漏), 这些信息会被记录,此测试标记为失败。

为了简单起见,Cmockery会在同一进程中执行所有的测试。因此,一个测试程序的所有测试用例,共用一个单独的地址空间, 也就是说,一个测试用例的内存崩溃,会导致整个测试程序的提前结束。

Cmockery的分配器的使用

allocate_module.c -------------------------------------------------------------------------------

 

 

 

 

allocate_module_test.c -------------------------------------------------------------------------------

 

 

 

 

模拟的函数

一个单元测试最好能将待测函数或模块从外部依赖中隔离。 这就会用到模拟函数,它通过动态或静态方式链接到待测模块中去。 当被测代码直接引用外部函数是,模拟函数必须静态链接。 动态链接是一个简单的过程,将一个函数指针放到一个表中,给待测模块中一个测试用例定义的模拟函数引用。

(模拟函数)返回值

为了简化模拟函数的实现,Cmockery 提供了给模拟函数的每个测试用例存放返回值的功能,使用的是 will_return() 函数。然后,这些值将通过每个模拟函数调用mock() 返回。 传给will_return() 的值,将分别添加到每个函数所特有的队列中去。连续调用 mock() ,将从函数的队列中移除一个返回值。 这使一个模拟函数通过多次调用mock() ,来返回(多个)输出参数和(一个)返回值成为可能。 此外,一个模拟函数多次调用(多个)返回值的做法也是可以的。

will_return()的使用

database.h -------------------------------------------------------------------------------

 

 

customer_database.c -------------------------------------------------------------------------------

 

 

 

customer_database_test.c -------------------------------------------------------------------------------

 

 

 

参数检测

除了存储模拟函数的返回值之外,Cmockery还提供了对模拟函数参数期望值的存储功能,使用的是 expect_*()函数,一个模拟函数的参数可以通过check_expected()宏来做有效的验证.

连续调用expect_*()宏,是用队列中的一个参数值来检测给定的参数。 check_expected()检测一个的函数参数,它与expect_*()相对应,即将出队的值。 如果参数检验失败,这个测试将标记为失败。 此外,如果调用check_expected()时,队列中没有参数值出队,测试也会失败。

expect_*()的使用

product_database.c -------------------------------------------------------------------------------

 

 

 

product_database_test.c -------------------------------------------------------------------------------

 

 

 

测试状态

Cmockery允许每个测试用例多次装载和卸载函数的做法, 装载函数,通过unit_test_setup()unit_test_setup_teardown() 宏给出, 支持多个测试用例公共的通用初始化; 此外,卸载函数,通过unit_test_teardown()unit_test_setup_teardown() 宏,给出一个测试用例在执行失败情况下的代码路径。

unit_test_setup_teardown()的使用

key_value.c -------------------------------------------------------------------------------

 

 

 

 

key_value_test.c -------------------------------------------------------------------------------

 

 

 

实例

一个很小基于命令行的计算器程序calculator.c
与计算器程序的测试程序calculator_test.c ,它包含了本文所涉及的所有特性的一个实例。


  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值