モック オブジェクトは、一部のプログラム ユニットの詳細な動作テストを行うための優れたアプローチを導入します。モックされた依存関係をテストされたユニットに渡し、依存関係で正常に動作するかどうかを確認するだけです。
2 つのクラス A と B があるとします。
public class A
{
private B b;
public A(B b)
{
this.b = b;
}
public void DoSomething()
{
b.PerformSomeAction();
if(b.State == some special value)
{
b.PerformAnotherAction();
}
}
}
public class B
{
public BState State { get; private set; }
public void PerformSomeAction()
{
//some actions
State = some special value;
}
public void PerformAnotherAction()
{
if(State != some special value)
{
fail(); //for example throw new InvalidOperationException();
}
}
}
クラス B が単体テスト TestB でテストされているとします。
クラス A を単体テストするには、B をそのコンストラクターに渡す (状態ベースのテストを行う) か、B のモックを渡す (動作ベースのテストを行う) ことができます。
2 番目のアプローチ (たとえば、A の状態を直接検証できず、間接的に検証できる) を選択し、単体テスト TestA (B への参照を含まない) を作成したとします。
したがって、インターフェイス IDependency を導入すると、クラスは次のようになります。
public interface IDependency
{
void PerformSomeAction();
void PerformAnotherAction();
}
public class A
{
private IDependency d;
public A(IDependency d)
{
this.d = d;
}
public void DoSomething()
{
d.PerformSomeAction();
if(d.State == some special value)
{
d.PerformAnotherAction();
}
}
}
public class B : IDependency
{
public BState State { get; private set; }
public void PerformSomeAction()
{
//some actions
State = some special value;
}
public void PerformAnotherAction()
{
if(State != some special value)
{
fail(); //for example throw new InvalidOperationException();
}
}
}
単体テスト TestB は次のようなものです。
[TestClass]
public class TestB
{
[TestMethod]
public void ShouldPerformAnotherActionWhenDependencyReturnsSomeSpecialValue()
{
var d = CreateDependencyMockSuchThatItReturnsSomeSpecialValue();
var a = CreateA(d.Object);
a.DoSomething();
AssertSomeActionWasPerformedForDependency(d);
}
[TestMethod]
public void ShouldNotPerformAnotherActionWhenDependencyReturnsSomeNormalValue()
{
var d = CreateDependencyMockSuchThatItReturnsSomeNormalValue();
var a = CreateA(d.Object);
a.DoSomething();
AssertSomeActionWasNotPerformedForDependency(d);
}
}
Ok。これは開発者にとって嬉しい瞬間です。すべてがテストされ、すべてのテストがグリーンです。すべてが良いです。
しかし!
誰かがクラス B のロジックを変更すると (たとえば、 if(State != some special value) を if(State != another value) に変更する)、TestB のみが失敗します。
この男はこのテストを修正し、すべてが再びうまくいくと考えています。
しかし、B を A のコンストラクターに渡そうとすると、A.DoSomething は失敗します。
その根本的な原因は、モック オブジェクトです。B オブジェクトの古い動作を修正しました。B がその動作を変更したとき、モックはそれを反映しませんでした。
それで、私の質問は、 B のモックを B の動作の変更に追従させる方法ですか?