C单元测试之使用cmockery

发表于:2009-10-20 14:24

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:51Testing软件测试网采编

  这么久以来一直没有找到一款很好的支持mock测试的C语言单元测试工具包,但前不久在一网友的评论中得知:去年Google曾发布了一款c语言的轻量级单元测试framework -- “cmockery”,cmcokery很小巧,对其他开源包没有依赖,对被测试代码侵入性小;它支持mock test,同样也可以支持常规的单元测试

  之前在博客中曾描述过C语言实现mock的一个思路,不过和cmockery对比起来,当时我的思路显然还处于初级阶段,而cmockery则走到了更高级,使用起来也更为简便。

  还是以我上一篇文章中的代码来举例,利用cmockery来对biz.c进行mock test。

  应用层被测试代码不变:

  /* biz.h */
  #ifndef BIZ_H
  #define BIZ_H
  #include <stdio.h>
  int biz_operation(char *fname);
  #endif
  /* biz.c */
  #include "biz.h"
  int biz_operation(char *fname) {
  FILE *fp = NULL;
  fp = fopen(fname, "r");
  if (fp == NULL) {
  printf("fail to open fle!\n");
  return 1;
  } else {
  printf("succeed to open file!\n");
  return 0;
  }
  }

  利用cmockery改造测试代码如下:

  /* test.c */
  #include <stdarg.h>
  #include <stddef.h>
  #include <setjmp.h>
  #include <stdio.h>
  #include "cmockery.h"
  #include "biz.h"
  FILE *fopen(const char *filename, const char *mode) {
  return (FILE*)mock();
  }
  void test_biz_operation_return_succ(void **state) {
  will_return(fopen, 0x1234);
  assert_true(biz_operation("foo.txt") == 0);
  }
  void test_biz_operation_return_fail(void **state) {
  will_return(fopen, NULL);
  assert_true(biz_operation("foo.txt") == 1);
  }
  int main() {
  const UnitTest tests[] = {
  unit_test(test_biz_operation_return_succ),
  unit_test(test_biz_operation_return_fail),
  };
  return run_tests(tests);
  }
  gcc  biz.c test.c -I ./ -I {YOUR_CMOCKERY_INSTALL_DIR}/include/google -L {YOUR_CMOCKERY_INSTALL_DIR}/lib -lcmockery

  执行a.out结果如下:

  test_biz_operation_return_succ: Starting test
  succeed to open file!
  test_biz_operation_return_succ: Test completed successfully.
  test_biz_operation_return_fail: Starting test
  fail to open fle!
  test_biz_operation_return_fail: Test completed successfully.
  All 2 tests passed

  在测试代码中override了C标准库中fopen的实现,代码很简单,就是调用一个mock,然后根据返回值类型做一个强制类型转换。那么执行起来后mock究竟会返回什么值呢?这个值你可以任意设定,看到下面test_biz_operation_return_xx中的 will_return宏了吗,在will_return中你可以设定fopen中mock()调用的返回值:will_return(fopen, 0x1234)或will_return(fopen, NULL); 是不是思路清晰了许多了呢,没错。cmockery就是通过在will_return中设置mock的返回值,并在执行fopen这类被mock的函数接口中通过接口实现中的mock调用将你设定的值返回出来,从而控制被测试接口biz_operation的执行路径和执行结果,以达到mock test的目的。

  cmockery的源代码行数不到3K,你阅读一下will_return和mock的源代码就一目了然了。大致思路应该是:在堆上分配一块内存,用来存储你在will_return中设定的返回值,用函数名字符串做索引;在mock()中则通过调用mock的函数的名字去匹配,得到已经设定好的存储在堆内存上的那个值,并在转型后返回。

  以上是cmockery支持的对通用函数返回值的 mock,cmockery还支持mock function的parameters checking、setup和teardown、assert failure和dynamic memory allocation的mock等,cmockery的manual中有细致说明。不过原理都类似,在上面也都说过了。不过有些机制对被测试代码还是有一定侵入性的。cmockery虽好,但是毕竟是针对C语言的,就无法逃过链接阶段符号resolved的问题,测试上面简单的代码还好,如果测试大工程中某复杂源代码文件中的接口时,链接时就会有些麻烦,所以工程源代码组织的扁平化、接口功能单一化、包含和清晰的调用关系都会大大有助于实施mock单元测试,否则一旦你的biz_operation接口功能很复杂,调用了很多其他接口,实现很冗长的话,那么你的mock测试同样也会很麻烦,这时你需要做的就应该是重构你的代码,将复杂的biz_operation拆分开了。

  另外cmockery的安装很简单,遵循常规的configure->make->make install,这里不再贽述了。

《2023软件测试行业现状调查报告》独家发布~

精彩评论

  • happyb060218
    2011-5-12 18:07:25

    在测试代码中override了C标准库中fopen的实现?我override我自己写的函数,居然报multiple definition。。。不解

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号