基本单元测试和C,我该如何开始?

时间:2009-01-17 11:03:52

标签: c linux unit-testing tdd check-framework

在StackOverflow上阅读了相当多的主题后, 我得出结论,我应该采取某种形式的 测试驱动开发/单元测试(或至少探索该区域)。

既然我们在谈论Linux下的c代码, 我决定试试check (我不知道这是不是正确的选择,但是如果它没有用,我可以随后尝试其他的东西)。

但是由于单元测试和单元测试框架的概念对我来说是全新的, 我开始在一个非常小的测试代码上做一些单元测试(但我完全迷失了,感觉就像我错过了一些东西)。

这是我到目前为止所做的,我创建了以下文件:

  • main.c,一个只调用名为my_pow的函数并打印结果的主函数。
  • my_pow.c,包含函数my_pow。
  • my_pow.h
  • my_pow_test.c,我想我应该在这里放置my_pow函数的单位代码。

(所以“普通程序”是main.c,my_pow.c和my_pow.h。)

这是my_pow.c


#include "my_pow.h"
int my_pow(int a, int b)
{
    return (a*b);
}

然后我想在my_pow_test.c中我写了这样的东西:


#include <check.h>
#include "my_pow.h"

START_TEST (test_my_pow)
{
    /* unit test code */
}
END_TEST

//do I need some sort off main here that calls test_my_pow?

这基本上与the check manual第3.1章中的相同, 但仍然没有......

有人可以请我朝正确的方向推进我吗?

由于 约翰


更新:没有理由我尝试使用支票我只是觉得我应该从某个地方开始, 也许CUnit是一个更好的选择(我想我也会尝试,然后做出有根据的选择)。

更新:感谢@philippe间接指出在线文档只是事实的一半, 澄清文档所述内容的示例代码已经与check包一起安装。 在Ubuntu案例/ usr / share / doc / check / example / tests /

更新:创建代码示例,以便您通过查看他的第一个版本开始, 然后是第二个等等。这样你就可以按照他如何创建一个非常基本的测试用例/代码,从传统的TTD方式开始。

由于我的代码被破坏了,我希望单元测试证明这一点, 我作了一点欺骗,并测试了真正的战俘功能。 像这样:


START_TEST (test_my_pow1)
{
    int resultat = my_pow(3,3);
    int math     = pow(3,3);
    fail_unless ( resultat == math,
           "Error on 3^3 != %d (%d)",math, resultat);
}

但是将来我不会重现stdlibs中已有的内容: - )


相关:

取自搜索[c] [unit-testing]

3 个答案:

答案 0 :(得分:8)

您创建了第一个测试用例。现在您需要create a test suite(一组测试用例)和runner

我建议你首先尝试编译their example以验证您的环境,尽管他们的文档通过diff(源补丁)引入了新代码,我觉得这并不方便。


如果您决定尝试使用其他框架(我立即想到minunit),我可以指向您“tutorial”。

答案 1 :(得分:5)

我更倾向于使用CUnit,这是X-Unit系列测试框架的一部分。

它可以扩展到大型测试套件,并且已经使用多年,因此已经成熟。

你没有使用CUnit的任何理由?

HTH

欢呼声,

罗布

答案 2 :(得分:4)

我多年来一直在使用dejagnu而且喜欢它。

我开始将它用于嵌入式开发,因为它非常支持您运行测试程序的机器可能与构建测试程序的机器不同的概念。这样做的结果是,在多个平台上测试代码也得到了很好的支持。不确定这是否重要。 gcc测试套件使用它。我也用它来进行桌面开发。

dejagnu的基本想法是你

  • 将测试程序复制到“目标”(本地测试可以是〜/ tmp目录)
  • 启动测试程序
  • 将东西打印到控制台(作为测试程序的输入)
  • 解析测试程序的输出并将其与您期望的相匹配
  • 决定该输出是通过还是失败

一旦你完成了测试程序并编写了测试脚本,你最终会做到这样的事情:

$ runtest
                === foo Summary ===

# of expected passes            42
foo-test built Thu Jan 15 20:09:19 PST 2009
foo-test version 0.0.0.1
runtest completed at Sun Jan 18 08:29:13 2009

我到那里测试名为foo的库的方式是:

      
  • 假设库的源文件和包含文件位于〜/ src / foo
  • 中   
  • 创建一个名为〜/ src / foo / testsuite
  • 的目录   
  • 编写一个名为foo-test.c的测试程序,其中包含一个main()
  •   
          
    • 处理命令行参数
    •     
    • - 打印一个提示并坐在循环处理“命令”中,我在其中定义一个命令来测试我的库中的每个函数。这有点像命令shell,但特定于库。对于像my_pow这样的东西,我将命令定义为2参数。
    •     
    • 写一个dejagnu(这是Expect之上的另一层(http://expect.nist.gov/,它本身就是一个名为Tcl(http://www.tcl.tk/)函数的层,名为my_pow:
    •     
              
      • 有两个参数
      •       
      • 计算预期结果(在Tcl中)
      •       
      • 将“my_pow”发送到控制台
      •       
      • 从foo-test
      • 解析my_pow命令的输出       
      • 确定实际结果是否与预期结果匹配
      •       
      • 调用适当的dejagnu函数(通过或失败)
      •     
        

听起来很难,但事实并非如此。需要一点时间来决定在foo-test中要做多少工作与在Tcl中做多少工作。我最终使用相当数量的shell(例如bash)功能来执行诸如将文件复制到临时目录或查看我的程序生成的日志文件之类的操作。所以你最终会擅长这些东西。

就参考文献而言,有一本关于Expect的书,我认为这是潜入这一要求的要求:http://oreilly.com/catalog/9781565920903/index.html
在它与在线Tcl命令参考http://www.tcl.tk/man/tcl8.4/TclCmd/contents.htm和常见问题解答(http://www.psg.com/~joem/tcl/faq.html)之间,您就在那里。

祝你好运。

-DB