Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reset mock verification in Moq?

Setup as so:

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 } 

Basically I'd like to enter some code at the // stuff here to make the foo.Verify(x => x.Fizz(), Times.Never()) pass.

And because this probably constitutes moq/unit testing abuse, my justification is so I can do something like this:

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

Basically, I have a state object where a fair bit of work (both in terms of making various mock objects and other faffing around) is requires to push it into State1. Then I want to test the transition from State1 to State2. Instead of duplicating or abstracting the code I'd prefer to just re-use the State1 test, push it into State2 and perform my Asserts - all of which I can do except the verification calls.

like image 204
fostandy Avatar asked Nov 12 '10 10:11

fostandy


People also ask

What does MOQ verify do?

Verifies that all verifiable expectations have been met.

What can be mocked with MOQ?

Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation.


2 Answers

This is now supported in Moq

Use .Invocations.Clear() on the latest version of the library:

var foo = new Mock<foo>(); foo.Invocations.Clear(); 

Old answer

I think long after this post was created they added the functionality that the OP had asked for, there is a Moq extension method called Moq.MockExtensions.ResetCalls().

With this method you can do exactly what you wished as shown below:

[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()); } 
like image 160
stackunderflow Avatar answered Sep 21 '22 15:09

stackunderflow


I don't think you can reset a mock like this. Instead, if you know that Fizz should be called once when transitioning to state 1, you can do your verifies like this:

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

Having said that, I would still create two separate tests for this. As two tests, it's easier to see whether the transition into state 1 is failing, or the transition into state 2 is failing. Additionally, when tested together like this, if your transition into state 1 fails, the test method exits and your transition into state 2 doesn't get tested.

Edit

As an example of this, I tested the following code with xUnit:

[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");  } 

This test fails with the message, "Failed after State 2". This simulates what would happen if your method that pushes foo into State 2 calls Fizz. If it does, the second Verify will fail.

Looking at your code again, since you are calling one method to verify it does/does not call another method on the mock, I think you need to set CallBase to true so that the base DoStuffToPushIntoState2 is called rather than the mock's override.

like image 40
Jeff Ogata Avatar answered Sep 20 '22 15:09

Jeff Ogata