37

Let's assume a snippet of testing code:

Observable model = Class.forName(fullyQualifiedMethodName).newInstance();
Observer view = Mockito.mock(Observer.class);
model.addObserver(view);
for (Method method : Class.forName(fullyQualifiedMethodName).getDeclaredMethods())
{
  method.invoke(model, composeParams(method));
  model.notifyObservers();
  Mockito.verify(
    view, Mockito.atLeastOnce()
  ).update(Mockito.<Observable>any(), Mockito.<Object>any());
}

Mockito.verify method throws an exception if a method in a model hasn't invoked Observable.setChanged() method.

Problem: without adding loggers/System.print.out I can't realize what's the current method that has failed the test. Is there a way of having something similar to jUnit Assert methods:

Assert.assertEquals(
  String.format("instances %s, %s should be equal", inst1, inst2),
  inst1.getParam(), 
  inst2.getParam()
);

SOLUTION:

verify(observer, new VerificationMode()
{
  @Override
  public void verify(VerificationData data)
  {
    assertTrue(
        format(
            "method %s doesn't call Observable#setChanged() after changing the state of the model",
            method.toString()
        ),
        data.getAllInvocations().size() > 0);
  }
}).update(Mockito.<Observable>any(), Mockito.<Object>any());
Boris Pavlović
  • 63,078
  • 28
  • 122
  • 148

7 Answers7

29

This question is ancient, but Mockito v2.1.0+ now has a built-in feature for this.

verify(mock, description("This will print on failure")).someMethod("some arg");

More examples included from @Lambart's comment below:

verify(mock, times(10).description("This will print if the method isn't called 10 times")).someMethod("some arg");
verify(mock, never().description("This will print if someMethod is ever called")).someMethod("some arg");
verify(mock, atLeastOnce().description("This will print if someMethod is never called with any argument")).someMethod(anyString());
Joe Coder
  • 4,498
  • 31
  • 41
  • 11
    Using `org.mockito.Mockito.description` this way implies `times(1)`; you are verifying that the method is called, with the given arg, _exactly_ once. But you can do much more. If you want to verify it was called exactly 10 times: `verify(mock, times(10).description("This will print if the method isn't called 10 times")).someMethod("some arg");` or `verify(mock, never().description("This will print if someMethod is ever called")).someMethod("some arg");` or `verify(mock, atLeastOnce().description("This will print if someMethod is never called with any argument")).someMethod(anyString());` – Lambart Jan 03 '20 at 00:43
20

This does the trick (simple and clear):

try {
 verify(myMockedObject, times(1)).doSomthing();
} catch (MockitoAssertionError error) {
    throw new MockitoAssertionError("Was expecting a call to myMockedObject.doSomthing but got ", error);
}
tasomaniac
  • 10,234
  • 6
  • 52
  • 84
Armin
  • 1,367
  • 1
  • 12
  • 17
  • 6
    Passing the cause as second argument is usally better than concatenating the message. `throw new MockitoAssertionError("message", e)` – kapex Nov 04 '13 at 10:07
  • 2
    MockitoAssertionError doesn't have a constructor with the parameters MockitoAssertionError(String, Exception) I use `new AssertionError("message", exception)` instead since this is the exception type that is thrown by JUnit for assertions. – Alex Q May 13 '15 at 22:50
  • Since 2.1.0 there is a `MockitoAssertionError(MockitoAssertionError, String)` constructor. – knueser Apr 02 '21 at 17:01
6

You cannot do in mockito. Mockito syntax makes very easy to test expected behaviour, but it has no concept of test state.

What you're trying to do is to have some information that are not in the mocked object when the mocks fails expectations.

If you really want to do, I see 2 general ways: either you create your own verificationMode implementing the interface

org.mockito.verification;
public static interface VerificationMode

and adding a method like atLeastOnceMsd(String msg) that will show the message in case of failing or adding the current tested method in the model to the view object

for example with a similar line in the inner loop.

  view.setName("now we are testing " + method.getName());
Uberto
  • 2,712
  • 3
  • 25
  • 27
3

There isn't a direct API call that allows a message on verify. But I think if you change your verify signature to use the method object rather than Mockito.any(), the toString() on the Method class will kick in and give you what you want.

Something like this.

import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Matchers.eq;

...

Observable model = Class.forName("class name").newInstance();

verify(view, times(1)).update(eq(model), anyObject());

for (Method method : Class.forName("class name").getDeclaredMethods())
{
    method.invoke(model, composeParams(method));
    model.notifyObservers();
    verify(view, atLeastOnce()).update(eq(method), anyObject());
}
dom farr
  • 4,041
  • 4
  • 32
  • 38
  • Nice try, but it's not going to work. First method of the Observer#update(Object source, Object arg) is the model that is broadcasting the change not the method that has changed its state. – Boris Pavlović Nov 15 '10 at 16:20
  • Just add the expectation you want to see. If that includes another type of observable then so be it. – dom farr Nov 15 '10 at 16:33
  • You probably need to add more code that explains your class structure better. – dom farr Nov 15 '10 at 16:33
1

You could create matcher to print information on the current method. It's gonna be a bit clunky, but it will work print the method name when the verification fails.

iwein
  • 25,788
  • 10
  • 70
  • 111
1

There is org.mockito.internal.verification.Description which delegates to provided VerificationMode, but allows to override verification message.

Konstantin Berkov
  • 1,193
  • 3
  • 14
  • 27
1

you can use https://www.javadoc.io/doc/org.mockito/mockito-core/2.2.6/org/mockito/verification/VerificationMode.html#description(java.lang.String)
eg.

verify(mocked,times(1).description("This method is expected to invoke once")).someMethod();
George Kargakis
  • 4,940
  • 3
  • 16
  • 12