在Moq中重置模拟validation?

设置如下:

public interface IFoo { void Fizz(); } [Test] public void A() { var foo = new Mock<IFoo>(MockBehavior.Loose); foo.Object.Fizz(); foo.Verify(x => x.Fizz()); // stuff here foo.Verify(x => x.Fizz(), Times.Never()); // currently this fails } 

基本上我想在// stuff hereinput一些代码来使foo.Verify(x => x.Fizz(), Times.Never())通过。

因为这可能构成moq /unit testing滥用,所以我的理由是我可以这样做:

 [Test] public void Justification() { var foo = new Mock<IFoo>(MockBehavior.Loose); foo.Setup(x => x.Fizz()); var objectUnderTest = new ObjectUnderTest(foo.Object); objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup foo.Verify(x => x.Fizz()); // reset the verification here objectUnderTest.DoStuffToPushIntoState2(); // more lines of code foo.Verify(x => x.Fizz(), Times.Never()); } 

基本上,我有一个状态对象,在这个状态对象中,要做一些相当的工作(无论是在制作各种模拟对象还是在其他方面),都需要把它推进到状态1中。 然后我想testing从State1到State2的转换。 代替复制或抽象代码,我宁愿重新使用State1testing,将其推入到State2并执行我的断言 – 除了validation调用之外,我可以执行所有这些。

我不认为你可以像这样重新设置一个模拟。 相反,如果你知道Fizz在转换到状态1时应该被调用一次,你可以这样做你的validation:

 objectUnderTest.DoStuffToPushIntoState1(); foo.Verify(x => x.Fizz(), Times.Once()); // or however many times you expect it to be called objectUnderTest.DoStuffToPushIntoState2(); foo.Verify(x => x.Fizz(), Times.Once()); 

话虽如此,我仍然会为此创build两个单独的testing。 作为两个testing,可以更容易地看到转换到状态1是失败还是转换到状态2失败。 另外,当像这样一起testing时,如果转换到状态1失败,则testing方法退出,并且转换到状态2不会被testing。

编辑

作为一个例子,我用xUnittesting了下面的代码:

 [Fact] public void Test() { var foo = new Mock<IFoo>(MockBehavior.Loose); foo.Object.Fizz(); foo.Verify(x => x.Fizz(), Times.Once(), "Failed After State 1"); // stuff here foo.Object.Fizz(); foo.Verify(x => x.Fizz(), Times.Once(), "Failed after State 2"); } 

该testing失败,并显示消息“状态2失败”。 这模拟了如果将foo推入状态2调用Fizz方法会发生什么。 如果是,则第二次Verify将失败。

再次查看你的代码,因为你正在调用一个方法来validation它是否在模拟上调用另一个方法,所以我认为你需要将CallBase设置为true以便调用基本的DoStuffToPushIntoState2而不是模拟的覆盖。

我想在创build这个post很长时间之后,他们添加了OP所要求的function,还有一个叫做Moq.MockExtensions.ResetCalls()的Moq扩展方法。

用这个方法,你可以按照你所希望的完成任务,如下所示:

 [Test] public void Justification() { var foo = new Mock<IFoo>(MockBehavior.Loose); foo.Setup(x => x.Fizz()); var objectUnderTest = new ObjectUnderTest(foo.Object); objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup foo.Verify(x => x.Fizz()); foo.ResetCalls(); // *** Reset the verification here with this glorious method *** objectUnderTest.DoStuffToPushIntoState2(); // more lines of code foo.Verify(x => x.Fizz(), Times.Never()); } 

如果MOQ的人在听,我有一个情况,我需要重置validation也。 我在NUnittesting课上有大约200个testing。 SUT设置起来相当复杂(我们需要6个模拟器和其他一些设置代码)。 在我们的整个testing套件中,我们有大约7000个testing,并且存在内存问题,所以我试图消除内存需求。 我想把所有的模拟调用移动到TestFixtureSetUp而不是SetUp。 除less数情况下检查一个方法是否只被调用一次外,这种方法是有效的。 检查Times.Exactly(1)的第二个testing现在失败。 如果我可以重置validation,我可以重新使用模拟和更明智地使用内存。

我知道我可以将设置移到一个单独的方法。 请不要责备我。 我只是提出一个有效的情况下,能够重置validation将被使用。

我也目睹了Times.Exactly(1)使用MoQ进行unit testing的validation失败,一个“被称为2次”的错误信息。 我把这看作是MoQ中的一个错误,因为我希望在每次testing运行时都会有清晰的模拟状态。

我的工作是在testing设置中分配一个新的模拟实例和testing目标。

 private Mock<IEntityMapper> entityMapperMock; private OverdraftReportMapper target; [SetUp] public void TestSetUp() { entityMapperMock = new Mock<IEntityMapper>(); target = new OverdraftReportMapper(entityMapperMock.Object); } 

您可以使用callback方法而不是validation,并计数呼叫。

这在Moq快速入门页面上进行了演示,因此:

 // returning different values on each invocation var mock = new Mock<IFoo>(); var calls = 0; mock.Setup(foo => foo.GetCountThing()) .Returns(() => calls) .Callback(() => calls++); // returns 0 on first invocation, 1 on the next, and so on Console.WriteLine(mock.Object.GetCountThing()); 

取决于你使用哪个版本的Mock,我知道我们可以做到这一点

someMockObject.ResetCalls();

这确实是unit testing滥用,因为您正在一次testing中validation两件事情。 如果您将ObjectUnderTest初始化置于testing之外并进入常用设置方法,那么您的生活将会变得更加简单。 然后,你的testing变得更可读和相互独立。

除了生产代码以外,testing代码应该进行优化以实现可读性和隔离。 系统行为的一个方面的testing不应该影响其他方面。 重构通用代码到一个设置方法比尝试重置模拟对象要容易得多。

 ObjectUnderTest _objectUnderTest; [Setup] //Gets run before each test public void Setup() { var foo = new Mock<IFoo>(); //moq by default creates loose mocks _objectUnderTest = new ObjectUnderTest(foo.Object); } [Test] public void DoStuffToPushIntoState1ShouldCallFizz() { _objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup foo.Verify(x => x.Fizz()); } [Test] public void DoStuffToPushIntoState2ShouldntCallFizz() { { objectUnderTest.DoStuffToPushIntoState2(); // more lines of code foo.Verify(x => x.Fizz(), Times.Never()); } 

下一个方法适用于我(使用Moq.Sequence)

  public void Justification() { var foo = new Mock<IFoo>(MockBehavior.Loose); foo.Setup(x => x.Fizz()); var objectUnderTest = new ObjectUnderTest(foo.Object); objectUnderTest.DoStuffToPushIntoState1(); // this is various lines of code and setup foo.Verify(x => x.Fizz()); // Some cool stuff using (Sequence.Create()) { foo.Setup(x => x.Fizz()).InSequence(Times.Never()) objectUnderTest.DoStuffToPushIntoState2(); // more lines of code } } 

让我知道,如果它为你解决