今年夏天,我开发了一个用纯c语言编写的嵌入式系统。这是我所在公司接管的一个现有项目。我已经非常习惯使用JUnit在Java中编写单元测试,但不知道为现有代码(需要重构)和添加到系统中的新代码编写单元测试的最佳方法是什么。
有什么项目可以让单元测试纯C代码像使用JUnit测试Java代码一样简单吗?任何特别适用于嵌入式开发(交叉编译到arm-linux平台)的见解都将非常感谢。
今年夏天,我开发了一个用纯c语言编写的嵌入式系统。这是我所在公司接管的一个现有项目。我已经非常习惯使用JUnit在Java中编写单元测试,但不知道为现有代码(需要重构)和添加到系统中的新代码编写单元测试的最佳方法是什么。
有什么项目可以让单元测试纯C代码像使用JUnit测试Java代码一样简单吗?任何特别适用于嵌入式开发(交叉编译到arm-linux平台)的见解都将非常感谢。
当前回答
在开始寻找模拟函数的方法之前,我还没有深入测试遗留的C应用程序。我非常需要mock来将我想测试的C文件与其他C文件隔离开来。我试过cmock,我想我会采用它。
Cmock扫描头文件,并根据它找到的原型生成模拟函数。mock将允许您在完全隔离的情况下测试C文件。您所要做的就是将您的测试文件链接到模拟对象,而不是真正的对象文件。
cmock的另一个优点是,它将验证传递给模拟函数的参数,并允许您指定模拟函数应该提供的返回值。这对于在函数中测试不同的执行流非常有用。
测试由典型的testA()、testB()函数组成,您可以在其中构建期望、调用函数来测试和检查断言。
最后一步是为unity的测试生成一个运行器。Cmock绑定到统一测试框架。Unity和其他单元测试框架一样容易学习。
很值得一试,而且很容易掌握:
http://sourceforge.net/apps/trac/cmock/wiki
更新1
我正在研究的另一个框架是cmock。
http://code.google.com/p/cmockery/
它是一个支持单元测试和模拟的纯C框架。它不依赖于ruby(与Cmock相反),也很少依赖于外部库。
它需要更多的手工工作来设置模拟,因为它不生成代码。这并不代表现有项目的大量工作,因为原型不会有太大的变化:一旦有了mock,就暂时不需要更改它们(这是我的例子)。额外的类型提供了对模拟的完全控制。如果有什么你不喜欢的,你只需改变你的mock。
不需要特别的测试人员。您只需要创建一个测试数组,并将其传递给run_tests函数。这里也有更多的手工工作,但我绝对喜欢自包含自治框架的想法。
此外,它还包含了一些我不知道的漂亮的C技巧。
总的来说,cmock需要对mock有更多的理解才能开始。例子可以帮助你克服这个问题。看起来它可以用更简单的机制来完成这项工作。
其他回答
我编写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有效。
如果你熟悉JUnit,那么我推荐CppUnit。 http://cppunit.sourceforge.net/cppunit-wiki
这是假设你有c++编译器来做单元测试。如果没有,那么我必须同意亚当·罗森菲尔德的观点,支票就是你想要的。
您可能还想看看libtap,这是一个输出任何测试协议(TAP)的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();
}
我不使用框架,我只是使用自动工具“检查”目标支持。实现一个“main”并使用assert。
我的测试目录Makefile.am(s)看起来像这样:
check_PROGRAMS = test_oe_amqp
test_oe_amqp_SOURCES = test_oe_amqp.c
test_oe_amqp_LDADD = -L$(top_builddir)/components/common -loecommon
test_oe_amqp_CFLAGS = -I$(top_srcdir)/components/common -static
TESTS = test_oe_amqp
cmock网址:http://code.google.com/p/cmockery/