web-dev-qa-db-ja.com

ユニットテストC ++:何をテストするか?

TL; DR

優れた有用なテストを書くのは難しく、C++ではコストが高くなります。経験豊富な開発者が何をいつテストするかについての理論的根拠を共有できますか?

ロングストーリー

以前はチーム全体でテスト駆動開発を行っていましたが、私たちにはうまくいきませんでした。私たちは多くのテストを行っていますが、実際のバグやリグレッションがあるケースをカバーするようには思われません。これは通常、ユニットが相互作用しているときに発生し、孤立した動作からではありません。

これは、多くの場合、ユニットレベルでのテストが非常に難しいため、TDDの実行を停止し(実際に開発を高速化するコンポーネントを除く)、代わりに、より多くの時間をかけて統合テストのカバレッジを増やしました。小規模な単体テストは実際のバグを検出することはなく、基本的にはメンテナンスのオーバーヘッドにすぎませんが、統合テストは努力する価値がありました。

今、私は新しいプロジェクトを継承しており、それをテストする方法について疑問に思っています。これはネイティブC++/OpenGLアプリケーションであるため、統合テストは実際にはオプションではありません。しかし、C++でのユニットテストは、Java(明示的にvirtualを明示的に作成する必要がある)の場合よりも少し難しく、プログラムはオブジェクト指向ではないので、 tいくつかのものをモック/スタブします。

私はテストを書くためにいくつかのテストを書くためだけにバラバラにして全体をOO化したくありません。だから私はあなたに尋ねています:私は何のためにテストを書くべきですか?例えば。:

  • 頻繁に変更されることが予想される関数/クラス?
  • 手動でテストするのが難しい関数/クラス?
  • 簡単にテストできる関数/クラスですか?

敬意を表したいくつかのC++コードベースを調査して、それらがどのようにテストされているかを調べ始めました。現在、Chromiumのソースコードを調べていますが、コードからテストの根拠を抽出するのが困難です。人気のあるC++ユーザー(委員会の委員、本の作者、Google、Facebook、Microsoftなど)がこれにどのように取り組んでいるかについての良い例や投稿があれば、それは非常に役立ちます。

更新

これを書いて以来、私はこのサイトとWebの周りで自分の方法を検索してきました。良いものを見つけました:

残念なことに、これらはすべてJava/C#中心です。 Java/C#で多数のテストを作成することは大きな問題ではないため、通常、メリットがコストを上回ります。

しかし、上で書いたように、C++では難しいです。特に、コードベースがそれほどOOでない場合は、ユニットテストを適切にカバーするために、物事を大幅に混乱させる必要があります。たとえば、私が継承したアプリケーションには、OpenGLの上の薄いレイヤーであるGraphics名前空間があります。すべてのエンティティをテストするために-すべてが直接その機能を使用します-これをインターフェイスとクラスに変換し、すべてのエンティティに挿入する必要があります。それはほんの一例です。

したがって、この質問に答えるときは、テストを書くためにかなりの投資をしなければならないことを覚えておいてください。

20
futlib

まあ、単体テストはほんの一部です。統合テストは、チームの問題を解決するのに役立ちます。統合テストは、あらゆる種類のアプリケーション、およびネイティブアプリケーションとOpenGLアプリケーション用に作成できます。 Steve FreemannとNat Pryceによる "Growing Object Oriented Software Guided by Tests"(eg http://www.Amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627)をチェックしてください。 )。 GUIとネットワーク通信を備えたアプリケーションの開発を順を追って説明します。

テスト駆動ではなかったソフトウェアのテストは別の話です。 Michael Feathersの「レガシーコードで効果的に機能する」を確認してください(http://www.Amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052)。

5
EricSchaefer

C++でTDDを実行していないのでコメントできませんが、コードの予想される動作をテストする必要があります。実装は変更される可能性がありますが、動作は(通常は?)同じままです。 Java\C#中心の世界では、これはpublicメソッドのみをテストし、予想される動作のテストを記述し、実装前にそれを実行することを意味します(通常は、実行するよりも良いと言えます:))。

2
Dante

TDDが「うまくいかなかった」のは残念です。それがどこを曲がるかを理解する鍵だと思います。 TDDがどのように機能しなかったのか、何を改善できたのか、なぜ問題が発生したのかを再確認して理解してください。

したがって、もちろん、単体テストは発見したバグをキャッチしませんでした。それが一種のポイントです。 :-)インターフェースがどのように機能するか、およびそれらが適切にテストされていることを確認する方法を検討することにより、そもそもバグの発生を防止したため、これらのバグは見つかりませんでした。

答えるには、あなたが質問したように、あなたが結論したように、テストされるように設計されていないユニットテストコードは難しいです。既存のコードの場合、単体テスト環境ではなく機能テスト環境または統合テスト環境を使用する方が効果的です。特定の領域に焦点を合わせて、システム全体をテストします。

もちろん、新しい開発はTDDの恩恵を受けます。新しい機能が追加されると、TDDのリファクタリングは新しい開発のテストに役立ち、同時にレガシー機能の新しい単体テストの開発も可能になります。

2
Bill Door