Appropriate Use of Mockito’s Reset Method

javamocking

I have a private method in my test class that constructs a commonly used Bar object. The Bar constructor calls someMethod() method in my mocked object:

private @Mock Foo mockedObject; // My mocked object
...

private Bar getBar() {
  Bar result = new Bar(mockedObject); // this calls mockedObject.someMethod()
}

In some of my test methods I want to check someMethod was also invoked by that particular test. Something like the following:

@Test
public void someTest() {
  Bar bar = getBar();

  // do some things

  verify(mockedObject).someMethod(); // <--- will fail
}

This fails, because the mocked object had someMethod invoked twice. I don't want my test methods to care about the side effects of my getBar() method, so would it be reasonable to reset my mock object at the end of getBar()?

private Bar getBar() {
  Bar result = new Bar(mockedObject); // this calls mockedObject.someMethod()
  reset(mockedObject); // <-- is this OK?
}

I ask, because the documentation suggests resetting mock objects is generally indicative of bad tests. However, this feels OK to me.

Alternative

The alternative choice seems to be calling:

verify(mockedObject, times(2)).someMethod();

which in my opinion forces each test to know about the expectations of getBar(), for no gain.

Best Answer

I believe this is one of the cases where using reset() is ok. The test you are writing is testing that "some things" triggers a single call to someMethod(). Writing the verify() statement with any different number of invocations can lead to confusion.

  • atLeastOnce() allows for false positives, which is a bad thing as you want your tests to always be correct.
  • times(2) prevents the false positive, but makes it seem like you are expecting two invocations rather than saying "i know the constructor adds one". Further more, if something changes in the constructor to add an extra call, the test now has a chance for a false positive. And removing the call would cause the test to fail because the test is now wrong instead of what is being tested is wrong.

By using reset() in the helper method, you avoid both of these issues. However, you need to be careful that it will also reset any stubbing you have done, so be warned. The major reason reset() is discouraged is to prevent

bar = mock(Bar.class);
//do stuff
verify(bar).someMethod();
reset(bar);
//do other stuff
verify(bar).someMethod2();

This is not what the OP is trying to do. The OP, I'm assuming, has a test that verifies the invocation in the constructor. For this test, the reset allows for isolating this single action and it's effect. This one of the few cases with reset() can be helpful as. The other options that don't use it all have cons. The fact that the OP made this post shows that he is thinking about the situation and not just blindly utilizing the reset method.