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

发布于 2024-07-12 04:21:29 字数 2365 浏览 10 评论 0原文

在 StackOverflow 阅读了很多帖子之后, 我得出的结论是我应该采取某种形式 测试驱动开发/单元测试(或至少探索该领域)。

既然我们谈论的是 Linux 下的 C 代码, 我决定尝试检查 (我不知道这是否是正确的选择,但如果不好我以后可以尝试其他方法)。

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

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

  • main.c,一个仅调用名为 my_pow 的函数并打印结果的 main。
  • 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?

这与 检查手册第3.1章, 但仍然没有......

有人可以把我推向正确的方向吗?

谢谢 约翰


更新:我没有理由尝试使用检查,我只是想我应该从某个地方开始, 也许 CUnit 是一个更好的选择(我想我也会尝试一下,然后做出明智的选择)。

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

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

由于我的代码被破坏了,我希望通过单元测试来证明这一点, 我做了一些作弊,并针对真实的 pow 函数进行了测试。 像这样的事情:


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);
}

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


相关:

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

After reading quite some threads here at StackOverflow,
I have come to the conclusion that I should adopt to some form of
test driven development/unit test (or at least explore the area).

And since we are talking about c code under Linux,
I decided to give check a try
(I don't know if this is the right choice but if it's no good I can always try something else later on).

But since this concept of unit test and unit test frameworks is totally new to me,
I started out to do some unit test on a really small test code (but I was totally lost anyway and it felt like I was missing something).

This is what I have done so far, I created the following file:

  • main.c, a main that only calls a function called my_pow and prints the result.
  • my_pow.c, contains the function my_pow.
  • my_pow.h
  • my_pow_test.c, I figured that I should place the unit code for the my_pow function here.

(So the "normal program" is the main.c, my_pow.c and my_pow.h.)

This is my_pow.c


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

Then I figured that in my_pow_test.c I put something like this:


#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?

This is basically the same as in the check manual chapter 3.1,
but still not....

Could someone please push me in the right direction?

Thanks
Johan


Update: No reason why I tried to use check I just thought I should start somewhere,
maybe CUnit is a better choice (I think I would try that as well and then make a educated choice).

Update: Thanks @philippe for indirectly pointing out that the on-line documentation is only half of the truth,
the example code that clarifies what the documentation talks about was already installed with the check package.
In the Ubuntu case /usr/share/doc/check/example/tests/

Update: The code example was created so that you started out by looking at his first version,
then the second one etc etc. So that you could follow how he creates a very basic test case/code from nothing up to something that is useful in a traditional TTD way.

And since my code was broken and I wanted the unit test to prove this,
I cheated a little and tested against the real pow function.
Something like this:


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);
}

However in the future I will not reproduce what is already in the stdlibs :-)


Related:

taken from searching [c] [unit-testing].

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

别靠近我心 2024-07-19 04:21:30

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

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

你有什么理由不选择 CUnit?

HTH

干杯,

罗布

I'd be more inclined to go with CUnit which is part of the X-Unit series of test frameworks.

It's scalable to large suites of tests and has been in use for many years, hence mature.

Any reason why you didn't go with CUnit?

HTH

cheers,

Rob

魂归处 2024-07-19 04:21:30

我多年来一直使用 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),你就差不多了。

祝你好运。

-D B

I've been using dejagnu for years and love it.

I started using it for embedded development because it supports very well the concept that the machine on which you're running the test program may be different than the machine on which you build the test program. A consequence of this is that testing code on multiple platforms is also well supported. Not sure if that's important. The gcc testsuite uses it. I use it for desktop development as well.

The basic idea with dejagnu is that you

  • copy the test program to the "target" (which for local testing could be the ~/tmp directory)
  • start the test program
  • print stuff to the console (which acts as input to the test program)
  • parse the output from the test program and match it with what you expect
  • decide whether that output means pass or fail

Once you've got the test program and the test scripts written, you end up doing something like this:

$ 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

The way I get there for testing a library named foo is:

  • assume the source and include files for the library are in ~/src/foo
  • create a directory named ~/src/foo/testsuite
  • write a test program named foo-test.c that has a main() that
    • processes command line args
    • - prints a prompt and sits in a loop processing "commands" where I define a command to test each function in my library. This is sort of like a command shell but specific to the library. For something like my_pow I'd define the command to take 2 args.
    • write a dejagnu (which is another layer on top of Expect (http://expect.nist.gov/, which is itself a layer on top of Tcl (http://www.tcl.tk/) function called my_pow that:
      • takes two arguments
      • calculates the expected result (in Tcl)
      • sends "my_pow " to the console
      • parses the output of the my_pow command from foo-test
      • determines whether the actual result matches the expected result
      • calls the appropriate dejagnu function (pass or fail)

Sounds hard, but it's not. It takes a little while to decide how much work to do in foo-test vs. how much to do in Tcl. I end up using a fair amount of shell (e.g. bash) functionality to do things like copy files to temp directories or look at the log files that my programs generate. So you end up getting good at all this stuff.

As far as references, there's one book on Expect that I'd say is a requirement for diving into this: http://oreilly.com/catalog/9781565920903/index.html.
Between that and an online Tcl command reference http://www.tcl.tk/man/tcl8.4/TclCmd/contents.htm and FAQ (http://www.psg.com/~joem/tcl/faq.html), you're pretty much there.

Good luck.

-DB

落花随流水 2024-07-19 04:21:29

您创建了第一个测试用例。 现在您需要创建一个测试套件 (一组测试用例)和一个 runner

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


如果您决定尝试使用另一个框架(我立即想到minunit ),我可以向您指出“教程”。

You created a first test case. Now you need to create a test suite (a group of test cases) and a runner.

I would recommend you try to compile their example first to validate your environment, although their documentation introduces new code via diff (source patch) which I do not find very convenient.


If ever you decide to try with another framework (minunit came to my mind immediately), I can point you to a "tutorial".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文