この質問が非常に長い間存在し、 Roy Osherove の "The Art of Unit Testing" に基づいた答えをまだ誰も提供していないことに驚いています。
「3.1 スタブの紹介」では、スタブを次のように定義しています。
スタブは、システム内の既存の依存関係 (またはコラボレーター) の制御可能な代替品です。スタブを使用すると、依存関係を直接処理せずにコードをテストできます。
また、スタブとモックの違いを次のように定義しています。
モックとスタブについて覚えておくべき主なことは、モックはスタブと同じですが、モック オブジェクトに対してアサートするのに対し、スタブに対してアサートしないということです。
Fake は、スタブとモックの両方に使用される名前です。たとえば、スタブとモックの違いを気にしない場合などです。
Osherove がスタブとモックを区別する方法は、テスト用の偽物として使用されるクラスは、スタブまたはモックの両方である可能性があることを意味します。どちらが特定のテストに適しているかは、テストでチェックをどのように記述するかによって完全に異なります。
- テストがテスト中のクラスの値をチェックするとき、または実際には偽物以外の場所で、偽物がスタブとして使用されました。テスト対象のクラスが使用する値を提供しただけで、呼び出しによって返された値を介して直接、または呼び出しの結果として (何らかの状態で) 副作用を引き起こすことによって間接的に行われます。
- テストが偽物の値をチェックするとき、それはモックとして使用されました。
クラス FakeX がスタブとして使用されるテストの例:
const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);
cut.SquareIt;
Assert.AreEqual(25, cut.SomeProperty);
はまったく使用しないため、fake
インスタンスはスタブとして使用されます。Assert
fake
テスト クラス X がモックとして使用されるテストの例:
const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);
cut.SquareIt;
Assert.AreEqual(25, fake.SomeProperty);
この場合、Assert
は の値をチェックしfake
、その偽物をモックにします。
もちろん、これらの例は非常に不自然ですが、この区別には大きなメリットがあると思います。これにより、自分のものをどのようにテストしているか、およびテストの依存関係がどこにあるかを認識できます。
Osherove の意見に同意する
純粋な保守性の観点から、モックを使用した私のテストでは、モックを使用しない場合よりも多くの問題が発生します。それが私の経験ですが、私は常に何か新しいことを学んでいます。
偽物に対するアサートは、テスト対象ではないクラスの実装にテストが大きく依存するようになるため、避けたいものです。これは、クラスActualClassUnderTest
の実装がClassUsedAsMock
変更されたため、クラスのテストが壊れ始める可能性があることを意味します。そして、それは私に悪臭を放ちます。のテストは、が変更されたActualClassUnderTest
場合にのみ中断する必要があります。ActualClassUnderTest
フェイクに対して assert を書くことは、特に TDD サブスクライバーのモックイスト タイプの場合は一般的であることを認識しています。私は、古典派の陣営で Martin Fowler にしっかりと賛成しており ( Martin Fowler の「モックはスタブではない」を参照)、Osherove と同様に、相互作用テスト (偽物に対してアサートすることによってのみ実行できます) をできるだけ避けています。
ここで定義されているモックを避けるべき理由を楽しく読むには、「fowler mockist classicist」をググってください。たくさんの意見が見られます。