web-dev-qa-db-ja.com

ユニットテストの効率を最大化するには、C ++ユニットテストのコードをどのように編成する必要がありますか?

  • この質問は、ユニットテストフレームワークについてnotです。
  • この質問は、ユニットテストの作成についてnotです。
  • この質問はwhereについてUT記述されたコードを記述し、それをコンパイルして実行する方法/時期/場所についてです。

レガシーコードを効果的に使用する で、Michael Feathersは次のように主張しています。

優れた単体テスト...高速に実行

そしてそれ

実行に1/10秒かかるユニットテストは、低速のユニットテストです。

これらの定義には意味があると思います。 また、一連のnit Testsと一連のThose Code Tests That LongかかるTakesを別々に保持する必要があることも示唆していると思いますが、それはあなたが支払う価格だと思います(非常に)高速に実行されている場合にのみ、単体テストを呼び出すため。

明らかに、C++での問題は、単体テストを「実行」することです(s)、 必ず:

  1. コードを編集します(現在の「サイクル」に応じて、本番または単体テスト)
  2. コンパイル
  3. リンク
  4. ユニットテスト実行可能ファイルを開始(s

編集する (奇妙な最終投票後):詳細に入る前に、ここで要点をまとめてみます。

C++ユニットテストコードを効果的に整理して、(テスト)コードの編集とテストコードの実行の両方を効率化するにはどうすればよいですか?


firstの問題は、whereを決定して、ユニットテストコードを次のように配置することです。

  • 関連する製品コードと組み合わせて編集および表示するのは「自然」です。
  • the unitのコンパイルサイクルを開始するのは簡単/迅速です

secondの関連する問題は、フィードバックが瞬時になるようにコンパイルするwhatです。

極端なオプション:

  • 各Unit-Test-Test-Unitは個別のcppファイルにあり、このcppファイルは(テストするソースコードユニットファイルと一緒に)個別にコンパイルおよびリンクされ、単一の実行可能ファイルにリンクされます。これにより、この1つのユニットテストが実行されます。 ]
    • (+)これにより、単一のテストユニットの起動(コンパイル+リンク!)時間を最小限に抑えることができます。
    • (+)1つのユニットのみをテストするため、テストは超高速で実行されます。
    • (-)スイート全体を実行するには、膨大な数のプロセスを開始する必要があります。管理が問題になる可能性があります。
    • (-)プロセス開始のオーバーヘッドが見えるようになります
  • 反対側は、テストごとに1つのcppファイルを持つことになりますが、すべてのテストcppファイルは(テストするコードと共に)1つの実行可能ファイルにリンクされます(モジュールごと/プロジェクトごと/選択してください)。
    • (+)変更されたコードのみがコンパイルされるため、コンパイル時間はまだ問題ありません。
    • (+)実行するexeが1つしかないため、スイート全体を簡単に実行できます。
    • (-)オブジェクトを再コンパイルするたびに再リンクがトリガーされるため、スイートのリンクには時間がかかります。
    • (-)(?)スーツの実行には時間がかかりますalthoughすべての単体テストが高速であれば、時間は問題ありません。

では、実際のC++ユニットテストはどのように処理されますか?それを毎晩実行するだけの場合、2番目の部分は重要ではありませんが、最初の部分、つまりUTコードを製品コードに「結合」する方法、つまり開発者が両方に焦点を合わせておくことが「自然」であることは常に重要だと思います(そして、開発者がUTコードに焦点を合わせている場合、それを実行したいと思うでしょう。 。)

実世界のストーリーと経験は高く評価されています!

ノート:

  • この質問は意図的に未指定のプラットフォームとmake/projectシステムを残します。
  • タグ付けされた質問UT&C++ は、始めるのに最適な場所ですが、残念ながら、あまりにも多くの質問、特に回答は、詳細または特定のフレームワークに重点を置いています。
  • 少し前に、ブーストユニットテストの構造について 同様の質問 に回答しました。この構造は、「実際の」高速な単体テストには欠けていると思います。そして、私は他の質問が狭すぎるので、この新しい質問を見つけます。
48
Martin Ba

1つの実行可能ファイルにすべてのユニットテスト(モジュール用)があります。テストはグループに分けられます。テストランナーのコマンドラインで(テスト/グループ)の名前を指定することで、単一のテスト(またはいくつかのテスト)またはテストのグループを実行できます。ビルドシステムはグループ「ビルド」を実行でき、テスト部門は「すべて」を実行できます。開発者は、いくつかのテストを「BUG1234」のようなグループに入れることができます。1234は、自分が取り組んでいるケースの課題追跡番号です。

6
ur.

まず、「1)(本番)コードとユニットテストを編集する」には同意しません。一度に1つだけ変更する必要があります。それ以外の場合、結果が変化しても、どれが原因であるかがわかりません。

メインツリーを隠すディレクトリツリーに単体テストを配置するのが好きです。 /sources/componentA/alpha/foo.cc/objects/componentA/beta/foo.oがある場合、/UTest_sources/componentA/alpha/test_foo.cc/UTest_objects/componentA/beta/test_foo.oのようなものが必要です。スタブ/モックオブジェクトとテストに必要なその他のソースには同じシャドウツリーを使用します。いくつかのEdgeケースが存在しますが、このスキームは物事を大幅に簡略化します。優れたエディターマクロは、問題のソースと共にテストソースを簡単に引き上げることができます。優れたビルドシステム(GNUMakeなど)は、両方をコンパイルし、1つのコマンド(make test_foo)でテストを実行できます。また、膨大な数のこのようなプロセス(最後にテストされてからソースが変更されたプロセスのみ)を管理できます。非常に簡単です(これらのプロセスを開始するオーバーヘッドが問題になることは一度もありませんでした。O(N)です)。

同じフレームワークで、多数のオブジェクトをリンクして多数のテストを実行する、より大規模なテスト(もはやユニットテストではない)を使用できます。トリックは、ビルド/実行にかかる時間でこれらのテストをソートし、それに応じて毎日のスケジュールに組み込むことです。必要に応じて、1秒以下のテストを実行してください。 10秒のテストを開始してストレッチします。 5分のテストと休憩。 30分テストと昼食に行きます。 6時間のテストと帰宅。あなたが多くの時間を浪費していることに気付いた場合。小さなファイルを1つだけ変更した後で巨大なテストを再リンクすると、間違って実行されます。リンクが瞬時であったとしても、要求されなかったときに長いテストを実行することになります。

6
Beta