アルファベットAの文字をアルファベットBにできるだけ訳してみようとするアプリケーションを作ったとしましょう。すべての単体テストが成功するはずですか?
言語Bは非常に複雑なので、これは必ずしも成功しません。しかし、あなたはおおよその音訳を取得します。
はどのようにあなたが20から30パーセントが失敗することを期待することを考慮すると、この場合にはユニットテストを構築するのでしょうか?
アルファベットAの文字をアルファベットBにできるだけ訳してみようとするアプリケーションを作ったとしましょう。すべての単体テストが成功するはずですか?
言語Bは非常に複雑なので、これは必ずしも成功しません。しかし、あなたはおおよその音訳を取得します。
はどのようにあなたが20から30パーセントが失敗することを期待することを考慮すると、この場合にはユニットテストを構築するのでしょうか?
あなたのユニットテストが成功することが常に目標でなければなりません。あなたがそれを使用する方法では、ソフトウェアの重大なエラーと予想される翻訳のエラーとを区別することはできません。
私は両方の分離することを示唆している:
失敗すると予想される単体テストは単体テストではありません。フィルタとして機能する評価関数を使用して成功の定義を変更し、 "十分に近い"かどうかを判断し、合格/不合格を判断する必要があります。あなたの翻訳者がより良くなるにつれ、あなたはフィルターのバーを上げることができます。
ユニットテストは確定的でなければなりません。テストに失敗すると、ソフトウェアの失敗を示すはずであり、が「意図したとおりに動作する」ものではありません。あなたのケースでは、変換が成功するか失敗するかを問わず、結果を確認してテストできる方法でデータを準備してください(が不具合を予想している場合は、常にテストが行われます) - あなたのテストが合格/不合格の時)。
私がこのような状況で学んだテクニックは、機能的(または決定論的)なコードの部分だけをテストすることです。もちろん、決定論的な部分と非決定論的な部分を分離するのが難しい部分です。これを表現する簡略な方法は、「機能的にリファクタリングする」ことです。これは、決定的なコードの部分を切り離し、それらの部分をテストすることを意味します。
シナリオベースのコンテキストビットについては、レガシーコード(およびオープンソースユニットテストライブラリApprovalTests)を使用してテストを行う場合、この手法の適用についてはblogポストをお読みください。
ここで興味深いさらに別の手法は、「理論に基づく」テストです。詳細については、blogの投稿をご覧ください。
単体テストが失敗する唯一の理由は、タイミングが関係する場合がほとんどです(主に電子回路がテストされている場合)。しかし、そのような場合でも、単体テストからタイミング問題を取り除くことが目標である。可能であれば、タイムアウトまたは他のタイミングの問題を拡張/切り替えることによって、それが不可能な場合、それは十分に文書化されるべきです。タイミング問題を除去し、テストは確定的にする
別の方法、すなわち外部インタフェースメソッドが返すこと値を設定することができ、いくつかの注入法では、すべての外部インターフェイス用のスタブを書くことです。このように単体テストを設定することで、文字通りすべてのエラー条件をすべてテストすることができます。
(ストーリー:私はいくつかの単体テストが失敗するかもしれない会社で働いていましたが、重大なエラーかタイミングの問題かどうかを分析できる人はほんのわずかでした。最初の場所)。
+ *プログラムが指定された要件を満たしていることを検証する* acceptance *テストからプログラムの正当性を検証する* unit *テストを分離するための+1。 –