今年夏天,我开发了一个用纯c语言编写的嵌入式系统。这是我所在公司接管的一个现有项目。我已经非常习惯使用JUnit在Java中编写单元测试,但不知道为现有代码(需要重构)和添加到系统中的新代码编写单元测试的最佳方法是什么。
有什么项目可以让单元测试纯C代码像使用JUnit测试Java代码一样简单吗?任何特别适用于嵌入式开发(交叉编译到arm-linux平台)的见解都将非常感谢。
今年夏天,我开发了一个用纯c语言编写的嵌入式系统。这是我所在公司接管的一个现有项目。我已经非常习惯使用JUnit在Java中编写单元测试,但不知道为现有代码(需要重构)和添加到系统中的新代码编写单元测试的最佳方法是什么。
有什么项目可以让单元测试纯C代码像使用JUnit测试Java代码一样简单吗?任何特别适用于嵌入式开发(交叉编译到arm-linux平台)的见解都将非常感谢。
当前回答
我编写Libcut只是出于对现有C单元测试库的不满。它具有原语的自动类型字符串(不需要test_eq_int, test_eq_long, test_eq_short,等等…)对于原语和字符串只有两个不同的集合),并且由一个头文件组成。这里有一个简短的例子:
#include <libcut.h>
LIBCUT_TEST(test_abc) {
LIBCUT_TEST_EQ(1, 1);
LIBCUT_TEST_NE(1, 0);
LIBCUT_TEST_STREQ("abc", "abc");
LIBCUT_TEST_STRNE("abc", "def");
}
LIBCUT_MAIN(test_abc);
不过,它只对C11有效。
其他回答
谷歌拥有优秀的测试框架。https://github.com/google/googletest/blob/master/googletest/docs/primer.md
是的,据我所知,它将与普通C一起工作,即不需要c++功能(可能需要c++编译器,不确定)。
cmock网址:http://code.google.com/p/cmockery/
如果你还在寻找测试框架,CUnitWin32是Win32/NT平台的一个。
这解决了我在其他测试框架中遇到的一个基本问题。也就是说,全局/静态变量处于确定性状态,因为每个测试都是作为单独的进程执行的。
API完整性检查器- C/ c++库的测试框架:
An automatic generator of basic unit tests for a shared C/C++ library. It is able to generate reasonable (in most, but unfortunately not all, cases) input data for parameters and compose simple ("sanity" or "shallow"-quality) test cases for every function in the API through the analysis of declarations in header files. The quality of generated tests allows to check absence of critical errors in simple use cases. The tool is able to build and execute generated tests and detect crashes (segfaults), aborts, all kinds of emitted signals, non-zero program return code and program hanging.
例子:
fontconfig 2.8.0测试套件 FreeType 2.4.8的测试套件
我个人喜欢谷歌测试框架。
测试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并给出一个空的实现。这意味着测试文件独立于其余代码库进行编译和链接,并独立执行。
至于交叉编译代码,您需要在目标上使用良好的工具。我使用googletest交叉编译到PowerPC体系结构上的Linux来实现这一点。这是有意义的,因为您有一个完整的shell和os来收集结果。对于不太丰富的环境(我将其归类为没有完整操作系统的任何环境),您应该只在主机上构建和运行。无论如何您都应该这样做,这样您就可以作为构建的一部分自动运行测试。
我发现测试c++代码通常要容易得多,因为OO代码通常比过程性代码耦合得少(当然这在很大程度上取决于编码风格)。此外,在c++中,你可以使用依赖注入和方法重写等技巧来将接缝插入封装的代码中。
Michael Feathers有一本关于测试遗留代码的优秀书籍。在其中一章中,他介绍了处理非oo代码的技巧,我强烈推荐这些技巧。
编辑:我写了一篇关于单元测试过程代码的博客文章,源代码可以在GitHub上找到。
编辑:Pragmatic Programmers出版了一本新书,专门介绍了C代码的单元测试,我强烈推荐这本书。