c - 如何进行C代码的单元测试

  显示原文与译文双语对照的内容

今年夏天,我在一个嵌入式系统上工作,用直接的c语言编写。 这是我为公司工作的一个现有项目。 我已经习惯使用JUnit在Java中编写单元测试了,但是对于编写现有代码的单元测试和添加到系统中的新代码的最佳方式。

junit,是否有任何项目在外面这个单元测试纯C 代码尽单元测试Java代码怎样? 任何特别适用于嵌入式开发( cross-compiling到arm-linux平台)的洞察力都会受到极大的重视。

时间:

中的一个单元测试框架是检查 ;在C 中的单元测试框架列表可以在这里找到 ,并在下面复制。 根据你的运行库有多少标准库函数,你可能无法使用其中之一。

AceUnit

AceUnit ( 高级C 和嵌入式单元) 将自己作为一个舒适的C 代码 单元测试 框架。 它试图模仿 JUnit 4.x 并包括reflection-like功能。 AceUnit可以用于资源约束环境,比如 嵌入式软件开发,重要的是它在环境中运行良好,并且不能从 ansi/iso C 库调用单一标准的头文件。 它也有一个 Windows 端口。 它不使用叉来捕获信号,尽管作者已经表示了添加这种特性的兴趣。 查看 AceUnit主页标题。

GNU Autounit

检查相同的行,包括分叉在单独的地址空间( 事实上,最初的检查作者借用了 GNU Autounit的思想) 中运行单元测试。 GNU Autounit广泛使用 GLib,这意味着链接和需要特殊选项,但这可能不是一个大问题,尤其是当你已经使用GTK或者GLib时。 查看 GNU Autounit主页标题。

cUnit

也使用 GLib,但不保护单元测试的地址空间。

cUnit

标准C,有一个 Win32 GUI实现的计划。 当前不分叉或者保护单元测试的地址空间。 在早期开发中。查看 CUnit主页 web 。

最可爱

一个只包含一个. c 和一个. h 文件的简单框架,你可以将它放入源代码树。 查看最可爱的主页

CppUnit

C++的主要单元测试框架;你也可以使用它来测试C 代码。 它是稳定的,积极开发的,并且有一个GUI界面。 不使用CppUnit的主要原因是它是非常大的,并且你必须在 C++ 中编写测试,这意味着你需要一个 C++ 编译器。 如果这些听起来不像问题,那么当然值得考虑,以及其他 C++ 单元测试框架。 查看 CppUnit主页 web 。

embUnit

embUnit ( 嵌入式单元) 是嵌入式系统的另一个 单元测试 框架。 这个似乎被AceUnit取代了。 嵌入式单元主页

MinUnit

一组最小的宏,就是这样 ! 关键是要说明 单元测试 是多么容易。 查看 MinUnit主页标题。

CUnit

一个相当新的CUnit实现,显然还在早期开发中。 查看 CUnit,为先生。 Ando主页副标题。

我个人喜欢测试框架

测试C 代码的真正困难是打破了外部模块的依赖,这样你就可以用单位隔离代码。 当你试图获取遗留代码的测试时,这可能会有问题。 在这种情况下,我经常发现自己使用链接器在测试中使用存根函数。

这就是人们谈论"接缝"时所说的。 在C 中,惟一的选择是使用pre-processor或者链接器来模拟你的依赖关系。

我的一个C 项目中的典型测试套件可能如下所示:


#include"myimplementationfile.c"
#include <gtest/gtest.h>

//Mock out external dependency on mylogger.o
void Logger_log(...){}

TEST(FactorialTest, Zero) {
 EXPECT_EQ(1, Factorial(0));
}

注意,你实际上是在头文件包含C 文件并不是。 这给了访问所有静态数据成员的好处。 这里我模拟了我的记录器( 它可能在 logger.o 中,并给出一个空的实现) 。 这意味着测试文件独立于代码库的其余部分编译和链接,并独立执行。

至于cross-compiling代码,这个代码在目标上需要好的工具。 我已经在一个PowerPC架构上通过googletest交叉编译了这个。 这有意义,因为你有一个完整的shell和操作系统来收集结果。 对于较低的环境,你应该在主机上构建并运行。 你仍然应该这样做,这样你就可以作为构建的一部分自动运行测试。

我发现测试 C++ 代码通常容易得多,因为OO代码通常比程序的耦合更小。 另外在 C++ 你可以使用技巧如依赖注入和方法重写,让接缝成代码从原本没有封装。

迈克尔羽毛都有一个关于测试遗留代码 优秀书籍。 在一个章节中他介绍了处理non-OO代码的技术,我强烈建议。

在 gitub, 编辑: 我写过一个博客文章与源 available. 关于单元测试过程代码,

编辑: 有个新书徐徐吐出的语用程序员明确地处理开发中的单元测试代码哪个,我强烈推荐 。

Minunit 是一个难以置信的单元测试框架。 我正在使用它来 单元测试的微控制器代码。

我目前使用的是最可爱的单元测试 框架:

http://cutest.sourceforge.net/

它是嵌入式系统的理想之选,因为它非常轻量级和简单。 我没有问题,那就是它可以在目标平台上工作以及在桌面上。 除了编写单元测试之外,所需的全部是:

  • 无论你在哪里调用最可爱的例程都包含头文件
  • 要编译/链接到图像中的单个附加'c'文件
  • 一些简单的代码添加到到主要设置并调用单元测试- 一个特殊 main() 中就出现了这个函数,该函数会被整理如果定义了单元测试,而在生成过程中。

系统需要支持一个堆和一些listobject功能( 并不是所有嵌入式系统都有) 。 但它的代码十分简单,因此你可以可能在替代方案这些需求如果你的平台没有他们来工作。

对外部"c"{} 块的合理使用,它也支持测试 C++ 。

于这里technology,你还可能想看看相关 libtap ( 点击),一个C 测试框架,包括输出测试任何协议与各种工具良好集成,因而未来出去。 它主要用于动态语言世界,但它很容易使用并变得非常流行。

一个示例:


#include <tap.h>

int main () {
 plan(5);

 ok(3 == 3);
 is("fnord","eek","two different strings not that way?");
 ok(3 <= 8732,"%d <= %d", 3, 8732);
 like("fnord","f(yes|no)r*[a-f]$");
 cmp_ok(3,">=", 10);

 done_testing();
}

在我开始寻找一个模拟函数的方法之前,我没有远地测试遗留的C 应用程序。 我需要mock来隔离我想测试的C 文件。 我给CMock一个尝试,我想我会采用它。

Cmock扫描头文件并根据Prototype生成模拟函数。 mock将允许你以完全独立的方式测试一个C 文件。 你所要做的就是将测试文件与模拟链接起来,而不是真实的对象文件。

CMock的另一个优点是它将验证传递给mock函数的参数,并允许你指定mock应该提供的返回值。 这对测试函数中的不同执行流非常有用。

测试包括典型的testA(), testB() 函数,你可以在其中构建期望,调用函数来测试和检查断言。

最后一步是使用unity生成测试的跑步小人。 Cmock绑定到unity测试框架。 Unity与任何其他 单元测试 框架一样易于学习。

值得一试,而且很容易掌握:

http://sourceforge.net/apps/trac/cmock/wiki

更新1

我正在研究的另一个框架是 Cmockery 。

http://code.google.com cmockery/

它是一个纯C 框架,支持单元测试和模拟。 它没有对 ruby ( 与Cmock相反)的依赖,它对外部库的依赖很少。

安装mock需要更多手工工作,因为它没有代码生成。 这并不代表现有项目的大量工作,因为Prototype不会改变很多: 一旦你进行了模拟,你就不需要更改它们一段时间了。 额外的类型提供了对模拟的完全控制。 如果你不喜欢,你只需改变你的模拟。

不需要特殊的测试转轮。 你只需要创建一个测试数组并将它的传递给run_tests函数。 这里也有一些手工的工作,但我绝对喜欢自包含框架的概念。

另外它还包含一些我不知道的漂亮的C 技巧。

总体Cmockery需要更多的理解模拟来开始。 示例应该可以帮助你克服这里问题。 看起来它可以用更简单的机械来完成这项工作。

我说几乎跟ratkok一样,但是如果你对单元测试有一个嵌入的扭曲。。

Unity - 高度推荐的单元测试代码框架。

使用团结本文提到的书中的例子那是线程 TDD主要对嵌入式C written.

有一个优雅的单元测试框架,支持名为 cmocka的模拟对象。 它只需要标准的C 库,在一系列计算平台( 包括嵌入的) 和不同编译器上工作。

它还支持不同的消息输出格式,比如子单元,测试任何协议和 jUnit XML报告。

cmocka已经被创建,可以在嵌入式平台上工作,也有 Windows 支持。

一个简单的测试如下:


#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
 (void) state;/* unused */
}

int main(void) {
 const struct CMUnitTest tests[] = {
 cmocka_unit_test(null_test_success),
 };
 return cmocka_run_group_tests(tests, NULL, NULL);
}

API 是完全文档化的,并且几个示例是源代码的一部分。

要开始使用 cmocka,你应该在 LWN.net: 单元测试中阅读关于单元测试的文章

cmocka 1.0已经被释放 2015年02月 。

CUnit

于嵌入式C system,和相关 嵌入式单元是跨平台是单元测试 它的设计是从JUnit和CUnit以及更多的,然后对嵌入式的C 系统进行了修改。 嵌入式单元不需要 std C 库。 所有对象都分配给了const区域。

Tessy 自动化了单元测试的嵌入式软件。

在C 非常helpful,作为一个C 新手,我发现的幻灯片叫做 测试驱动开发之中 基本上,它使用标准 assert()&& 来传递消息,没有任何外部依赖。 如果有人习惯于一个完整的堆栈测试框架,这可能不会做:)

...