单元测试C代码

我在今年夏天用C语言写了一个嵌入式系统。这是一个现有的项目,我工作的公司已经接手了。 我已经习惯于使用JUnit编写Java单元测试,但是对于为现有代码编写单元测试(这需要重构)以及添加到系统中的新代码的最佳方式感到茫然。

有没有什么办法让单元测试纯C代码就像使用JUnit单元测试Java代码一样简单? 任何专门针对嵌入式开发(交叉编译到arm-linux平台)的见解都将不胜感激。


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

AceUnit

AceUnit(高级C和嵌入式单元)自称是一个舒适的C代码单元测试框架。 它试图模仿JUnit 4.x并包含类似反射的功能。 AceUnit可用于资源约束环境,例如嵌入式软件开发,重要的是,它可以在您不能包含单个标准头文件并且无法从ANSI / ISO C库调用单个标准C函数的环境中运行。 它也有一个Windows端口。 尽管作者表示有兴趣添加这样的功能,但它并不使用叉子来捕捉信号。 查看AceUnit主页。

GNU Autounit

与Check大致相同,包括在单独的地址空间中运行单元测试(实际上,Check的原作者从GNU Autounit借鉴了这个想法)。 GNU Autounit广泛使用GLib,这意味着链接等需要特殊选项,但这对您来说可能不是什么大问题,特别是如果您已经使用GTK或GLib。 请参阅GNU Autounit主页。

库尼特

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

库尼特

标准C,计划用于Win32 GUI实现。 目前没有分叉或以其他方式保护单元测试的地址空间。 在早期发展。 查看CUnit主页。

可爱

一个简单的框架,只有一个.c和一个.h文件,可以放到源代码树中。 请参阅CuTest主页。

CppUnit的

首要的C ++单元测试框架; 你也可以用它来测试C代码。 它稳定,积极开发,并具有GUI界面。 不使用CppUnit for C的主要原因首先是它很大,其次你必须用C ++编写你的测试,这意味着你需要一个C ++编译器。 如果这些听起来不是问题,那么绝对值得考虑,以及其他C ++单元测试框架。 请参阅CppUnit主页。

embUnit

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

MinUnit

一组最小的宏,就是这样! 关键是要展示单元测试代码是多么容易。 请参阅MinUnit主页。

CUO先生Ando先生

CUnit的实现是相当新的,显然还处于早期开发阶段。 查看CUnit安多先生的主页。

该清单最后于2008年3月更新。

其他:

CMocka

CMocka是支持模拟对象的C测试框架。 它很容易使用和设置。 CMocka官方主页。

标准

Criterion是一个跨平台的C单元测试框架,支持自动测试注册,参数化测试和理论,并且可以输出为多种格式,包括TAP和JUnit XML。 每个测试都在其自己的过程中运行,因此可以根据需要报告或测试信号和崩溃。 有关更多信息,请参阅Criterion主页。

HWUT

HWUT是一个通用的单元测试工具,对C语言有很好的支持。它可以帮助创建Makefiles,生成大量的测试用例,用最小的“迭代表”编码,沿着状态机行走,生成C-stub等等。 一般的方法非常独特:判定基于'好stdout / bad stdout'。 但比较功能很灵活。 因此,任何类型的脚本都可以用于检查。 它可能适用于任何可以产生标准输出的语言。 见HWUT主页。


我个人喜欢Google测试框架。

测试C代码的真正困难在于打破了外部模块的依赖关系,因此您可以用单位隔离代码。 当您尝试围绕遗留代码进行测试时,这可能尤其成问题。 在这种情况下,我经常发现自己使用链接器在测试中使用存根函数。

这是人们谈论“ 接缝 ”时所指的。 在C中,唯一的选择就是使用预处理器或链接器来嘲笑你的依赖关系。

我的一个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中,并给出一个空的实现,这意味着测试文件独立于代码库的其余部分进行编译和链接,并独立执行。

至于交叉编译代码,为了这个工作,你需要在目标上有好的设施。 我已经在PowerPC架构上将googletest与crosstest编译为Linux。 这是有道理的,因为你有一个完整的shell和os来收集你的结果。 对于较少丰富的环境(我将它归类为没有完整操作系统的任何东西),您应该在主机上构建并运行。 无论如何,你应该这样做,这样你就可以作为构建的一部分自动运行测试。

我发现测试C ++代码通常要容易得多,因为OO代码通常比程序更少耦合(当然,这很大程度上取决于代码风格)。 同样在C ++中,您可以使用像依赖注入和方法覆盖这样的技巧来将代码封装到代码中。

Michael Feathers有一本关于测试遗留代码的优秀书籍。 在一章中,他介绍了处理非OO代码的技术,我强烈建议。

编辑 :我写了一篇关于单元测试程序代码的博客文章,其源代码在GitHub上提供。

编辑 :有一本新书出自实用程序员专门解决单元测试C代码,我强烈建议。


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

链接地址: http://www.djcxy.com/p/8963.html

上一篇: Unit Testing C Code

下一篇: How should I unit test threaded code?