如何使用Moq调用类中的另一个方法

时间:2009-09-13 06:54:16

标签: moq

这似乎很简单,但我似乎无法让它发挥作用。

我有一个带有Save方法的类,它只调用另一个方法ShouldBeCalled()。我想验证,如果我调用Save(),其他方法ShouldBeCalled()至少执行一次。我以为我可以做到以下几点。

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());
    }
}

但我得到异常“模拟上的预期调用至少一次,但从未执行过:x =&gt; x.ShouldBeCalled()”

这只是一个猜测,但是Moq用它自己的版本重写了Save()方法,它忽略了我在真实对象的Save()方法中的任何东西。

4 个答案:

答案 0 :(得分:29)

您遇到此问题是因为您在嘲笑您正在测试的内容。这没有意义。

你是正确的,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();
    }
}

这里的关键教训是你模拟/存根你的测试需要运行什么,而不是你自己测试的。

希望这有帮助, 安德森

答案 1 :(得分:4)

尝试使用CallBase = true然后使用false。我运行了你的代码,它确实有用。

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

答案 2 :(得分:2)

是的,这可以做到。但是,您需要添加一行代码以使Moq跟踪是否确实调用了ShouldBeCalled方法。

以下内容将起作用:

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

安装方法设定了期望值。当您致电验证时,您要求Moq验证这些期望。如果您没有进行安装调用以创建对ShouldBeCalled方法的期望,那么Moq不会认为它是可跟踪的,因此当您尝试验证它时会很难。

答案 3 :(得分:1)

您可以使用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());
    }
}