いつ予期し、いつスタブするか?
質問
私は NMock2 を使用しており、一般的なモック フレームワークの概念を表す次の NMock クラスを作成しました。
Expect
:これは、モック化されたメソッドが何を返すかを指定し、呼び出しが行われなければテストが失敗することを示します (呼び出しを伴う場合)。VerifyAllExpectationsHaveBeenMet()
).Stub
:これは、モックされたメソッドが返すものを指定しますが、テストを失敗させることはできません。
では、いつどれをすればいいのでしょうか?
解決
多くのモック フレームワークは、モックとスタブの概念を、機能的にはほぼ同じであるとみなせるところまで近づけています。ただし、概念的な観点から、私は通常、次の規則に従おうとします。
- モック:テスト対象のオブジェクトの動作を明示的に検証しようとしている場合のみ (つまり、あなたのテストは、このオブジェクトがそのオブジェクトを呼び出す必要があることを示しています)。
- スタブ:いくつかの機能/動作をテストしようとしているが、それを機能させるためには、いくつかの外部オブジェクト (つまり、テストは、このオブジェクトが何かをしなければならないことを示していますが、副作用としてそのオブジェクトを呼び出す可能性があります)
これは、各単体テストで 1 つのことだけをテストするようにすると、より明確になります。確かに、1 回のテストですべてをテストしようとする場合は、すべてを期待した方がよいでしょう。ただし、特定の単体テストでチェックされる内容のみを期待することで、テストの目的が一目でわかるため、コードがより明確になります。
これのもう 1 つの利点は、変更から少しだけ隔離され、変更によって中断が生じた場合に表示されるエラー メッセージが改善されることです。言い換えれば、実装の一部を微妙に変更した場合、一連のテスト全体が壊れてノイズが発生するだけではなく、1 つのテスト ケースだけが壊れる可能性が高く、何が壊れているのかが正確にわかります。
編集:計算機オブジェクトがデータベースへのすべての追加を (擬似コードで) 監査するという、不自然な例に基づいた方がわかりやすいかもしれません...
public void CalculateShouldAddTwoNumbersCorrectly() {
var auditDB = //Get mock object of Audit DB
//Stub out the audit functionality...
var calculator = new Calculator(auditDB);
int result = calculator.Add(1, 2);
//assert that result is 3
}
public void CalculateShouldAuditAddsToTheDatabase() {
var auditDB = //Get mock object of Audit DB
//Expect the audit functionality...
var calculator = new Calculator(auditDB);
int result = calculator.Add(1, 2);
//verify that the audit was performed.
}
したがって、最初のテスト ケースでは、 Add
メソッドであり、監査イベントが発生するかどうかは気にしませんが、計算機は AuditDB 参照なしでは機能しないことがわかっているので、特定のテスト ケースを取得するための最小限の機能を提供するためにそれをスタブ化するだけです。働く。2 番目のテストでは、次のことを実行したときを具体的にテストします。 Add
, 、監査イベントが発生するため、ここでは期待値を使用します (結果が何であるかさえ気にしないことに注意してください。それはテスト対象ではないためです)。
はい、2 つのケースを 1 つに結合し、期待値を実行して結果が 3 であると主張することはできますが、その場合は 1 つの単体テストで 2 つのケースをテストすることになります。これにより、テストがより脆弱になり (テストを中断するために変更される可能性のある表面積が大きくなるため)、明確さが失われます (マージされたテストが失敗しても、何が問題なのかすぐには分からないため)。加算が機能していないのか、それとも監査が機能していないのか?)
他のヒント
"アクション、スタブクエリを期待"。呼び出しは、テスト対象のオブジェクト外の世界の状態を変更する必要がある場合は、それを期待します - あなたはそれが呼び出されるかを気に。それだけでクエリの場合は、その後、コールスタブ、システムの状態を変更することなく、一回または6回、それを呼び出すことができます。
もう一つ、区別がスタブと期待との間にあることがわかり、それは個々のコール、必ずしも全体のオブジェクトです。
うーん...私見それは単純にはできません:あなたのテストは、[保存]を呼び出しますあなたのプレゼンターを確保することについてであれば、期待ください。あなたのテストは、あなたのプレゼンターが保存アップスロー優雅場合に例外を処理する確保についてであれば、スタブを行います。
詳細については、Hanselman氏とOsherove の(の著者によってこのポッドキャストをチェックしてくださいユニットテストの芸術)