24

ここ StackOverflow でかなりのスレッドを読んだ後、何らかの形のテスト駆動型開発/単体テストを採用する (または少なくともその領域を調査する) 必要があるという結論に達しました。

Linux での C コードについて話しているので、チェックを試してみることにしました (これが正しい選択かどうかはわかりませんが、うまくいかない場合は、後でいつでも別のことを試すことができます)。

しかし、この単体テストと単体テスト フレームワークの概念は私にとってまったく新しいものだったので、非常に小さなテスト コードで単体テストを実行することから始めました (しかし、とにかく完全に道に迷い、何かが足りないように感じました)。

これは私がこれまで行ってきたことであり、次のファイルを作成しました。

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

これは基本的にチェックマニュアルの 3.1 章と同じですが、それでも違います....

誰かが私を正しい方向に押してくれませんか?

ありがとうヨハン


更新: check を使用しようとした理由はありません。どこかから始めるべきだと思っただけです。おそらく CUnit の方が良い選択です (私もそれを試してから、知識に基づいた選択をすると思います)。

更新: オンライン ドキュメントが真実の半分にすぎないことを間接的に指摘してくれた @philippe に感謝します。ドキュメントの内容を明確にするサンプル コードは、チェック パッケージと共に既にインストールされています。Ubuntu の場合 /usr/share/doc/check/example/tests/

更新: コード例は、彼の最初のバージョン、次に 2 番目のバージョンなどを見ることから始められるように作成されました。そのため、彼が非常に基本的なテスト ケース/コードを何もないところから何かに役立つものまで作成する方法をたどることができます。伝統的な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);
}

ただし、将来的には、すでに標準ライブラリにあるものを再現しません:-)


関連している:

検索から取得[c] [unit-testing]

4

3 に答える 3

9

最初のテスト ケースを作成しました。次に、テスト スイート(テスト ケースのグループ) とrunnerを作成する必要があります。

最初にサンプルをコンパイルして環境を検証することをお勧めしますが、ドキュメントには diff (ソースパッチ) を介して新しいコードが導入されていますが、これはあまり便利ではありません。


別のフレームワークを試すことにした場合 ( minunitがすぐに頭に浮かびました)、「チュートリアル」を参照できます。

于 2009-01-17T12:40:39.497 に答える
5

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

于 2009-01-17T11:53:47.097 に答える
4

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

于 2009-01-18T16:59:18.127 に答える