Moqを使用してクラス内の別のメソッドが呼び出されたことを確認する方法

StackOverflow https://stackoverflow.com/questions/1417048

  •  06-07-2019
  •  | 
  •  

質問

これは単純なもののように思えますが、動作させることができません。

別のメソッドShouldBeCalled()を呼び出すSaveメソッドを持つクラスがあります。 Save()を呼び出すと、他のメソッドShouldBeCalled()が少なくとも1回実行されることを確認したいと思います。次のことができると思いました。

public class ClassA
{
    public virtual void Save()
    {
        ShouldBeCalled();
    }

    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        var mockClassA = new Mock<ClassA>();
        mockClassA.Object.Save();

        mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());
    }
}

ただし、例外が発生します&quot;モックでの呼び出しが少なくとも1回必要ですが、実行されませんでした:x =&gt; x.ShouldBeCalled()&quot;

単なる推測ですが、MoqはSave()メソッドを独自のバージョンでオーバーライドし、実際のオブジェクトのSave()メソッド内にあるものはすべて無視します。

役に立ちましたか?

解決

テスト対象をwhat笑しているため、この問題が発生しています。これは意味がありません。

Moqがメソッドの実装を独自のものに置き換えることは正しいことです。その理由は、Moqを使用して、テストしているクラスではなく、テストしているクラスをモックすることになっているからです。

コードがこのように設計されている場合、このテストは適切です:

public class ClassA
{
    BusinessLogicClass bl;
    public ClassA(BusinessLogicClass bl)
    {
         this.bl = bl;
    }

    public void Save()
    {
        bl.ShouldBeCalled();
    }
}

public class BusinessLogicClass
{
    public virtual void ShouldBeCalled()
    {
        //This should get executed
    }
}

そして、ここにそのメソッドの正しいテストがあります:

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_ShouldCallShouldBeCalled()
    {
        //Arrange
        var mockBLClass = new Mock<BusinessLogicClass>();
        mockBLClass.Setup(x => x.ShouldBeCalled()).Verifyable();

        //Act    
        ClassA classA = new ClassA(mockBLClass.Object);
        classA.Save();

        //Assert
        mockBLClass.VerifyAll();
    }
}

ここでの重要な教訓は、自分がテストするものではなく、テストの実行に必要なものを模擬/スタブすることです。

これが役立つことを願って、 アンダーソン

他のヒント

CallBase = trueを使用してから、falseを使用してみてください。私はあなたのコードを実行し、それが動作します。

var mockClassA = new Mock<ClassA>();
mockClassA.CallBase = true;
mockClassA.Object.Save();
mockClassA.CallBase = false;
mockClassA.Verify(x => x.ShouldBeCalled(), Times.AtLeastOnce());

はい、これは可能です。ただし、ShouldBeCalledメソッドが実際に呼び出されたかどうかに関係なく、Moqで追跡するにはコード行を追加する必要があります。

次のようなものが機能します:

var mockClassA = new Mock<ClassA>();
mockClassA.Setup(x => x.ShouldBeCalled()).Verifiable();    
mockClassA.Object.Save();    
mockClassA.Verify(x => s.ShouldBeCalled(), Times.AtLeastOnce());

Setupメソッドは期待値を設定します。 Verifyを呼び出すと、Moqにこれらの期待値を検証するように求めています。 ShouldBeCalledメソッドの期待値を作成するためにSetup呼び出しを行わない場合、Moqはそれを追跡可能とは見なさないため、検証しようとすると失敗します。

CallBaseを使用して、テスト対象システムのメソッドをスタブ化できます。

[TestFixture]
public class ClassA_Test
{
    [Test]
    public void Save_Should_Call_ShouldBeCalled()
    {
        // Arrange
        var mockClassA = new Mock<ClassA>();
        mockClassA.CallBase = true; // this will call real methods unless the method is mocked/stubbed. 
        mockClassA.Setup(a => a.ShouldBeCalled());

        // Act
        mockClassA.Save();

        // Assert
        mockClassA.Verify(a => a.ShouldBeCalled(), Times.Once());
    }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top