首页 文章

单元测试C代码[关闭]

提问于
浏览
755

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

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

30 回答

  • 12

    Minunit是一个非常简单的单元测试框架 . 我正在用它来测试avr的微控制器代码 .

  • 1
  • 6

    LibU(http://koanlogic.com/libu)有一个单元测试模块,允许显式测试套件/案例依赖,测试隔离,并行执行和可自定义的报告格式化程序(默认格式为xml和txt) .

    该库是BSD许可的,包含许多其他有用的模块 - 网络,调试,常用数据结构,配置等 - 如果您在项目中需要它们...

  • 142

    作为C新手,我发现名为Test driven development in C的幻灯片非常有用 . 基本上,它使用标准 assert()&& 来传递消息,而没有任何外部依赖性 . 如果有人习惯了完整的堆栈测试框架,这可能不会做:)

  • 11

    在对目标进行测试之前,我使用RCUNIT对PC上的嵌入代码进行了一些单元测试 . 好的硬件接口抽象很重要,否则字节序和内存映射寄存器会杀了你 .

  • 26

    首先,看这里:http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C

    我公司有一个客户使用的C库 . 我们使用CxxTest(一个C单元测试库)来测试代码 . CppUnit也会起作用 . 如果你被困在C中,我会推荐RCUNIT(但CUnit也很好) .

  • 1
  • 0

    Michael Feather的书“有效地使用遗留代码”介绍了C开发过程中特定于单元测试的许多技术 .

    有一些与C相关的依赖注入技术,我还没有在其他地方看到过 .

  • 2

    我不使用框架,我只是使用autotools“检查”目标支持 . 实现“main”并使用assert(s) .

    我的测试目录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
    
  • 20

    您还可以查看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();
    }
    
  • 2

    CUnit

    Embedded Unit是嵌入式C系统的单元测试框架 . 它的设计是从JUnit和CUnit等复制而来,然后在某种程度上适用于嵌入式C系统 . 嵌入式单元不需要std C libs . 所有对象都分配给const区域 .

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

  • 0

    除了我明显的偏见

    http://code.google.com/p/seatest/

    是一个很好的简单方法来单元测试C代码 . 模仿xUnit

  • 2

    C中的一个单元测试框架是Check; C中的单元测试框架列表可以在here找到,并在下面复制 . 根据运行时具有的标准库函数数量,您可以使用或不使用其中一种 .

    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主页 . cUnit也使用GLib,但不分叉以保护单元测试的地址空间 . CUnit Standard C,计划实现Win32 GUI . 当前没有分叉或以其他方式保护单元测试的地址空间 . 在早期发展 . 请参阅CUnit主页 . CuTest一个简单的框架,只有一个.c和一个.h文件,你可以放入源代码树 . 请参阅CuTest主页 . CppUnit C的首要单元测试框架;你也可以用它来测试C代码 . 它稳定,积极开发,并具有GUI界面 . 主要原因没有首先使用CppUnit for C是非常大的,其次你必须用C编写测试,这意味着你需要一个C编译器 . 如果这些听起来不像是关注点,那么绝对值得考虑,以及其他C单元测试框架 . 请参阅CppUnit主页 . embUnit embUnit(嵌入式单元)是嵌入式系统的另一个单元测试框架 . 这个似乎被AceUnit取代了 . 嵌入式单元主页 . MinUnit一组最小的宏,就是这样!关键是要展示对代码进行单元测试是多么容易 . 请参阅MinUnit主页 . CUnit为Ando先生提供了一个相当新的CUnit实现,显然还处于早期开发阶段 . 请参阅安藤先生主页的CUnit . 此列表最后更新于2008年3月 .

    其他:

    CMocka

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

    标准

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

    HWUT

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

    维基百科在List of unit testing frameworks: C下提供了C单元测试框架的详细列表

  • 5

    一种使用的技术是使用C xUnit框架(和C编译器)开发单元测试代码,同时将目标系统的源维护为C模块 .

    确保定期在交叉编译器下编译C源代码,如果可能的话,自动进行单元测试 .

  • 7

    我们写了CHEAT(托管于GitHub),以便于实用性和便携性 .

    它没有依赖关系,不需要安装或配置 . 只需要头文件和测试用例 .

    #include <cheat.h>
    
    CHEAT_TEST(mathematics_still_work,
        cheat_assert(2 + 2 == 4);
        cheat_assert_not(2 + 2 == 5);
    )
    

    测试编译成一个可执行文件,负责运行测试并报告其结果 .

    $ gcc -I . tests.c
    $ ./a.out
    ..
    ---
    2 successful of 2 run
    SUCCESS
    

    它也有漂亮的颜色 .

  • 433

    Google拥有出色的测试框架 . https://github.com/google/googletest/blob/master/googletest/docs/primer.md

    是的,据我所知,它将适用于普通的C,即不需要C功能(可能需要C编译器,不确定) .

  • 4

    如果您熟悉JUnit,那么我推荐CppUnit . http://cppunit.sourceforge.net/cppunit-wiki

    假设你有c编译器来进行单元测试 . 如果没有,那么我必须同意亚当罗森菲尔德,检查是你想要的 .

  • 4

    读完Minunit之后,我认为更好的方法是在断言宏中进行测试,我使用的很像防御程序技术 . 所以我使用了Minunit与标准断言相同的想法 . 你可以在k0ga's blog看到我的框架(一个好名字可能是NoMinunit)

  • 2

    我将CxxTest用于嵌入式c / c环境(主要是C) .

    我更喜欢CxxTest,因为它有一个perl / python脚本来构建测试运行器 . 经过一个小坡度进行设置(由于您不必编写测试运行器,因此更小),它非常易于使用(包括样本和有用的文档) . 最多的工作是设置代码访问的“硬件”,这样我就可以有效地进行单元/模块测试 . 之后,很容易添加新的单元测试用例 .

    如前所述,它是一个C / C单元测试框架 . 所以你需要一个C编译器 .

    CxxTest User Guide CxxTest Wiki

  • 1

    CppUTest - 强烈建议的单元测试C代码框架 .

    本主题TDD for embedded C中提到的书中的示例是使用CppUTest编写的 .

  • 12

    我个人喜欢Google Test framework .

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

    这是人们在谈论“ seams ”时所指的 . 在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));
    }
    

    Note that you are actually including the C file and not the header file . 这提供了访问所有静态数据成员的优势 . 在这里,我模拟了我的 Logger (可能在logger.o中并给出一个空的实现 . 这意味着测试文件独立于代码库的其余部分进行编译和链接并单独执行 .

    至于交叉编译代码,为了使它工作,你需要在目标上有良好的设施 . 我已经通过googletest交叉编译到PowerPC架构上的Linux来完成此操作 . 这使得感觉因为你有一个完整的shell和操作系统来收集你的结果 . 对于不太丰富的环境(我将其归类为没有完整操作系统的任何东西),您应该只在主机上构建和运行 . 无论如何,您应该这样做,以便您可以作为构建的一部分自动运行测试 .

    我发现测试C代码通常要容易得多,因为OO代码通常比程序更少耦合(当然这在很大程度上取决于编码风格) . 同样在C中,您可以使用依赖注入和方法重写等技巧将接缝转换为以其他方式封装的代码 .

    迈克尔·费瑟斯有一个excellent book about testing legacy code . 在一章中,他介绍了处理非面向对象代码的技巧,我强烈推荐 .

    Edit :我写了blog post关于单元测试程序代码,source available on GitHub .

    Edit :有一个new book coming out from the Pragmatic Programmers专门用于测试单元测试C代码I highly recommend .

  • 124

    有一个优雅的C单元测试框架,支持名为cmocka的模拟对象 . 它只需要标准的C库,适用于各种计算平台(包括嵌入式)和不同的编译器 .

    它还支持不同的消息输出格式,如Subunit,Test Anything Protocol和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上的文章:Unit testing with mock objects in C

    cmocka 1.0已于2015年2月发布 .

  • 3

    如果您仍在寻找测试框架,CUnitWin32是Win32 / NT平台的一个 .

    这解决了我遇到的其他测试框架的一个基本问题 . 即全局/静态变量处于确定性状态,因为每个测试都作为单独的进程执行 .

  • 6

    我说和ratkok几乎一样但是如果你对单元测试有一个嵌入式扭曲那么......

    Unity - 强烈建议的单元测试C代码框架 .

    本主题TDD for embedded C中提到的本书中的示例是使用Unity(和CppUTest)编写的 .

  • 30

    API Sanity Checker - C / C库的测试框架:

    共享C / C库的基本单元测试的自动生成器 . 它能够生成合理的(在大多数情况下,但不幸的是并非所有情况下)参数输入数据,并通过分析头中的声明为API中的每个函数构成简单(“健全”或“浅”质量)测试用例 . 文件 . 生成的测试质量允许在简单的用例中检查是否存在严重错误 . 该工具能够构建和执行生成的测试并检测崩溃(段错误),中止,各种发出的信号,非零程序返回码和程序挂起 .

    例子:

  • 11

    如果您的目标是Win32平台或NT内核模式,您应该看一下cfix .

  • 4

    在开始寻找模拟函数的方法之前,我没有远远地测试遗留的C应用程序 . 我非常需要模拟来隔离我想要测试的C文件 . 我尝试了一下cmock,我想我会采用它 .

    Cmock扫描头文件并根据它找到的原型生成模拟函数 . 模拟将允许您完美隔离测试C文件 . 您所要做的就是将测试文件与模拟而不是真实的目标文件链接起来 .

    cmock的另一个优点是它将验证传递给模拟函数的参数,并且它将允许您指定模拟应提供的返回值 . 这对于测试函数中的不同执行流程非常有用 .

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

    最后一步是为统一的测试生成一个运行器 . Cmock与统一测试框架联系在一起 . Unity与任何其他单元测试框架一样容易学习 .

    非常值得一试,很容易掌握:

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

    Update 1

    我正在调查的另一个框架是Cmockery .

    http://code.google.com/p/cmockery/

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

    它需要更多的手动工作来设置模拟,因为它不会生成代码 . 这并不代表现有项目的大量工作,因为原型不会有太大变化:一旦你有了你的模拟,你就不需要改变它们一段时间(这是我的情况) . 额外的打字可以完全控制嘲笑 . 如果有什么你不喜欢的东西,你只需更改你的模拟 .

    不需要特殊的测试跑步者 . 您只需要创建一个测试数组并将其传递给run_tests函数 . 这里也有一些手工工作,但我绝对喜欢自包含自治框架的想法 .

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

    整体Cmockery需要更多地了解模拟才能开始 . 例子可以帮助你克服这一点 . 看起来它可以用更简单的机制来完成工作 .

  • 39

    我目前正在使用CuTest单元测试框架:

    http://cutest.sourceforge.net/

    它非常适合嵌入式系统,因为它非常轻巧和简单 . 我没有遇到让它在目标平台和桌面上工作的问题 . 除了编写单元测试外,所需要的只是:

    • 包含在您调用CuTest例程的任何位置的头文件

    • 要编译/链接到图像中的单个附加'C'文件

    • 将一些简单的代码添加到main以设置和调用单元测试 - 我只是在一个特殊的main()函数中使用它,如果在构建期间定义了UNITTEST,则会对其进行编译 .

    系统需要支持堆和一些stdio功能(并非所有嵌入式系统都具有) . 但是代码很简单,如果您的平台没有这些代码,您可能可以替代这些需求 .

    通过明智地使用extern“C”{}块,它也支持测试C就好了 .

  • 15

    Cmockery是最近推出的一个项目,它包含一个非常简单易用的C库,用于编写单元测试 .

  • 34

    我很惊讶,没有人提到Cutter (http://cutter.sourceforge.net/)你可以测试C和C,它与autotools无缝集成,并提供了一个非常好的教程 .

相关问题