C ++ユニットテストとCxxTestについて

最近では、1つのプロジェクトの開発中に、C ++で単体テストを作成するための便利なツールを見つけるという課題に直面しました。 この記事では、どのような結果が私の研究をより詳細に導きました。


ユニットテストを作成するための特定のツールに着手する前に、ユニット(またはユニット)テストとは何か、その基本原則、および一般に、このビジネスに個別のライブラリが必要な理由を判断しましょう。

したがって、この原則は、プログラムのソースコードの重要な関数またはメソッドごとに小さなテストを作成することです。 このアプローチは何をもたらしますか? まず、このようなテストを実施した後、すべての部品が個別に機能していると明確に言うことができます(「ミッシングエラー」の概念と混同しないでください)。 第二に、回帰テストを実施できます。 そして第三に、単体テストは、テストされた関数とクラスの使用方法の良い例です。 単体テスト-間接的な文書化の手段。

また、私の意見では、単体テストの原則についても触れたいと思います。 それらをリストします。

そのため、さまざまなルーチン操作(main()サポート、クラスインスタンスの作成、メッセージの表示など)を自動化するツールが必要です。 いくつかの要件を提示します。


現時点では、C ++で単体テストを作成するためのライブラリ(膨大な数の9000以上)があります。 ここに皆のために彼らの好みに手段があります。 それらのいくつかを簡単にリストします。

Boost ::テスト
BoostはC ++で最も有名な(そして大きな)ライブラリの1つであり、Boost :: Testはそれに含まれており、マクロ上に構築されたテストフレームワークです。
Boostの最初の知り合いはあまり良い思い出を残しませんでした-ドキュメントがかさばり、扱いにくいです。さらに、このモンスターはかなりの重量があります(はい、ライブラリ全体をプロジェクトにアタッチする必要はありません。Boost:: Testを使用できますが、ダウンロードできます完全にある必要があります)。
ドキュメントから小さなテスト例を示します:

Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  1. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  2. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  3. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  4. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  5. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  6. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  7. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  8. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  9. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  10. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  11. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  12. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  13. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  14. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  15. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  16. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }
  17. Copy Source | Copy HTML #include <boost/test/minimal.hpp> Int add( int i, int j ) { return i+j; } Int test_main( int , char *[ ] ) // note the name! { BOOST_CHECK( add( 2 , 2 ) == 4 ); // #1 continues on error BOOST_REQUIRE( add( 2 , 2 ) == 4 ); // #2 throws on error if ( add( 2 , 2 ) != 4 ) BOOST_ERROR( "Ouch..." ); // #3 continues on error if ( add( 2 , 2 ) != 4 ) BOOST_FAIL( "Ouch..." ); // #4 throws on error if ( add( 2 , 2 ) != 4 ) throw "Oops..." ; // #5 throws on error return add( 2 , 2 ) == 4 ? 0 : 1 ; // #6 returns error code }


QTestLib
また、それほど有名ではないライブラリですが、レビューによるとかなり複雑であり、テストのためにすべてのQTをプルすることは正当化されません。

UnitTest ++
悪くて人気のあるものではありませんが、ドキュメントは貧弱です。

そして最後に:
Cxxtest
私の意見では、単体テストを書くための最高のxUnitライクなライブラリの1つです。
機能の:

欠点の:


それでは、CxxTestの使用方法を見てみましょう。
  1. * .hファイルを作成する
  2. CxxTestから継承したクラスを作成する:: TestSuite
  3. testMethod(void)メソッドを実装します(重要:最初の単語は必ずテストする必要があります-そうでない場合、システムはそれをテストとして認識しません)
    Copy Source | Copy HTML
    1. クラス MyTestpublic CxxTest :: TestSuite
    2. {
    3. 公開
    4. void testMethod( void
    5. {
    6. TS_ASSERT( 1 + 1 > 1 );
    7. TS_ASSERT_EQUALS( 1 + 1、2 );
    8. }
    9. };

  4. プリプロセッサを実行する
    Copy Source | Copy HTML
    1. #perl cxxtestgen.pl --error-printer -o runner.cpp MyTest.h
    2. MyTest.h-私たちが書いたテスト
    3. runner.cpp-出力ファイル(メイン()関数がその中に作成されます)
    4. cxxtestgen.plまたはcxxtestgen.py-プリプロセッサ

  5. ...そしてコンパイル
    Copy Source | Copy HTML
    1. #g ++ -o runner runner.cpp


成功した場合、次の形式の式を取得します。
Copy Source | Copy HTML
  1. #./runner
  2. 1つのテストを実行します。OK!


さて、ソースコードに何か正しくない場合、CxxTestは丁寧に指示します。
Copy Source | Copy HTML
  1. #./runner
  2. 2つのテストを実行します。
  3. MyTest.h:15:期待(2 * 2 == 5)、 見つかった (4!= 5)
  4. 2つのテストのうち1つに失敗しました
  5. 成功率:50%


まとめると。


CxxTestは、C ++で単体テストを作成するための非常に便利なフレームワークです。さらに、プログラマの作業を容易にするだけでなく、テストの正しい作成にも貢献します。
CxxTestにリストされている機能に加えて、テストを視覚化するためのシンプルなインターフェイスを(プログレスバーの形で)簡単に作成できます。また、モックオブジェクトもサポートされています。

PS
Inversionの招待に感謝します。

Source: https://habr.com/ru/post/J69160/


All Articles