这似乎很简单,但我似乎无法让它发挥作用。
我有一个带有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()方法中的任何东西。
答案 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());
}
}