3

例:

public bool Save(MyObj instance)
{
    if (instance.IsNew)
    {
        this.repository.Create(instance);
    }
    else
    {
        this.repository.Update(instance);
    }
}

次のことを確認するテストをMoqで作成するにはどうすればよいですか。

  1. プロパティIsNewが読み取られていること
  2. またはが呼び出されCreate()Update()
4

2 に答える 2

3

頭のてっぺんから:IsNewプロパティが読み取られていることを確認します。

var mock = new Mock<MyObj>();
mock.Setup(m => m.IsNew).Returns(true).Verifiable();
//...
sut.Save(mock.Object);
//...
mock.Verify();

上記の例では、IsNewプロパティがを返すtrueため、作成パスが使用されます。

CreateメソッドまたはUpdateメソッドのいずれかが呼び出されたことを確認するには、その機能にフックする必要があります。リポジトリは静的クラスのようです。この場合、テストダブルに置き換えることはできませんが、コードを間違った方法で読み取っている可能性があります...テストダブル(モック)に置き換えることができる場合は、上で概説したのと同じ原理を使用できます。

Saveメソッドが呼び出された後にリポジトリの状態を調べることができる場合は、状態ベースのテストによって、2つのコードパスのどちらがたどられたかを判断できる場合があります。

2つのコードパスの結果の間に外部から観察できる違いがない場合は、この特定の実装の詳細をテストしない方がよいでしょう。過剰指定テストと呼ばれるアンチパターンにつながる可能性があります。このアンチパターンや他の多くの単体テスト関連の詳細については、優れた書籍xUnitTestPatternsを参照してください。


編集: リポジトリのテストは同じ方法で行うことができます:

var myObjMock = new Mock<MyObj>();
myObjMock.Setup(m => m.IsNew).Returns(true);

var repositoryMock = new Mock<Repository>();
repositoryMock.Setup(m => m.Create(myObjMock.Object)).Verifiable();

var sut = new SomeClass(repositoryMock.Object);
sut.Save(myObjMock.Object);

repositoryMock.Verify();

検証可能への呼び出しが鍵です。これがない場合、Moqのデフォルトの動作は、邪魔にならないようにし、可能な限り最善を尽くし、可能な限り例外をスローしないことです。

検証可能と呼ぶとき、あなたはその特定の振る舞いを期待するようにモックに指示します。ベリファイを呼び出したときにその期待が満たされていない場合、例外がスローされるため、テストは失敗します。

于 2009-07-08T17:57:13.903 に答える
3

残念ながら、私には解決策があります。

あなたがしなければならないのは、intあなたが0に設定したローカル変数を持っていて、それからモックがそれをインクリメントすることです。最後に、その名前が0より大きいかどうか(または問題によっては正確に1より大きいかどうか)を確認する必要があります。

// Arrange
int count = 0;
Mock<Repository> mock = new Mock<Repository>();
mock.Setup<bool>(m => m.Create(It.IsAny<MyObj>())).Callback(() => count++);
mock.Setup<bool>(m => m.Update(It.IsAny<MyObj>())).Callback(() => count++);
// Act
...
// Assert
Assert.AreEqual(count, 1);

2つのテストがあります。プロパティIsNewをにtrue設定するものと、に設定するものfalse

于 2009-07-08T20:59:40.617 に答える