Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I set up a Mockito mock with expectations (verify) at instantiation time?

Verifying that an expected method has run in Mockito usually goes something like this:

when(mockFoo.someMethod()).thenReturn(someValue);
// run test
verify(mockFoo, times(n)).someMethod();

Is there any way for me to specify the verification at the time I create the mock. In something like EasyMock I can do:

mockFoo = EasyMock.createMock(Foo.class);
EasyMock.expect(mockFoo.someMethod()).times(n).andReturn(someValue);
// then run test

My use case is that I have a commonly reused test dependency that I'd like to mock (the doesFooMethodAndReturnBar5Times mock), but with Mockito I don't have a way to enforce the verification on it.

like image 491
Nathan Avatar asked Dec 11 '25 03:12

Nathan


1 Answers

UPDATE: This answer has changed significantly, as strict mocks are available in Mockito 2 and enforcement for strict stubs will be available by default in Mockito 3. Use the strict and lenient modes to configure these mocks and stubs and look at mockito issue 769 for docs and progress.

Prior to Mockito 2, this is not something Mockito could do easily. EasyMock's default strict mocks ensure that (1) unexpected interactions fail immediately and (2) all expected interactions happen; Mockito didn't have a setting for either, aside from verifyNoMoreInteractions (which doesn't fail immediately, but rather at end-of-test). This is a philosophical design decision on Mockito's part, and see this thread where the Mockito originators discuss it further.


In fact, Mockito's when syntax depends on it allowing unexpected interactions, because the unexpected interaction tells Mockito which method was called:

when(mockFoo.someMethod()).thenReturn(someValue);
//   ^^^^^^^^^^^^^^^^^^^^  Java calls this first to get an argument for when,
//                         which is how Mockito knows which method to stub:
//                         it's always the last one called.

EasyMock mocks that are tolerant of unexpected calls are named "nice mocks"; a big selling point of Mockito is that mocks are nice by default, so they are generally tolerant of calls unrelated to the behavior being tested. This does make debugging a bit harder, as Mockito will not fail immediately on an unexpected interaction the way that EasyMock would, but it also makes the tests less brittle—it is more likely that a safe change will still break a test because an EasyMock mock got an unexpected call. Before proceeding further, check with your team that they'll be happy with your choice here: Strict mock semantics are relatively new for Mockito and the broken assumptions there may be as big a deal as a framework change. (To that point, after seeing the alternative, they may let you use EasyMock after all!)


To use strict mocks in Mockito 2+, see the syntax and libraries in Mockito issue 769. This might be a good reason to upgrade from Mockito 1.x.

To emulate strict mocks in Mockito 1.x, you'll need to set a default Answer that fails the test, and also establish your correct behavior using only doVerb methods (doAnswer, doReturn, doThrow, etc). This syntax gives Mockito the warning it needs to deactivate your stubbed behavior. To create the default Answer, you can either set the behavior for a single method (preferred), or for all methods on a single mock.

public class ThrowingAnswer extends Answer<Object> {
  @Override public Object answer(InvocationOnMock invocation) {
    throw new AssertionError("Unexpected invocation: " + invocation);
  }
}

// apply to the entire object:
YourObject yourObject = Mockito.mock(YourObject.class, new ThrowingAnswer());

// or per-method:
YourObject yourObject = Mockito.mock(YourObject.class);
doAnswer(new ThrowingAnswer()).when(yourObject).scaryMethod(any());

Mockito will always return behavior on the last-defined matching chain, and will only use the default answer if no chains match, so you should be able to define any number of chains with doVerb methods to override that behavior.

like image 76
Jeff Bowman Avatar answered Dec 13 '25 16:12

Jeff Bowman