Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito: Wanted but not invoked

I have a following test method:

MyClass myClass= Mockito.mock(MyClass.class);
Mockito.when(myClass.methodUsedInMethodBeingTested(Matchers.any(MyTypeParam.class))).thenReturn(Collections.<X, Y> emptyMap());

assertNull(myClass.methodToTest(myObject));
Mockito.verify(myClass).methodUsedInMethodBeingTested(Matchers.any(MyTypeParam.class));

The methodUsedInMethodBeingTested is a method that I want to mock and return an empty map. But I am getting the failure message saying

Wanted but not invoked myClass.methodUsedInMethodBeingTested()

.

MyClass
{
   public XYZ methodToTest()
   {
    ....
    ....
    Map<X,Y> mp = methodUsedInMethodBeingTested(myTypeParam);
    .....
   }

   public Map<X,Y> methodUsedInMethodBeingTested(MyTypeParam myTypeParam)
   {
    .....
   }
}
like image 527
Vivin Avatar asked Feb 19 '16 17:02

Vivin


People also ask

What is difference between @mock and @injectmock?

@Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class. Annotated class to be tested dependencies with @Mock annotation.

What does thenReturn do in Mockito?

thenReturn or doReturn() are used to specify a value to be returned upon method invocation. //”do something when this mock's method is called with the following arguments” doReturn("a").

How Mockito works internally?

Mockito was released as an open-source testing framework under the MIT (Massachusetts Institute of Technology) License. It internally uses the Java Reflection API to generate mock objects for a specific interface. Mock objects are referred to as the dummy or proxy objects used for actual implementations.


2 Answers

You are invoking the methodToTest on the mock instance. Because you have not configured it otherwise, that just returns null, it doesn't try to invoke any of the actual method's implementation.

like image 36
Andy Turner Avatar answered Sep 23 '22 08:09

Andy Turner


You're misunderstanding what a mock is. When you're doing

MyClass myClass = Mockito.mock(MyClass.class);
// ...
assertNull(myClass.methodToTest(myObject));

You're not actually invoking methodToTest on your real object. You're invoking methodToTest on the mock, which by default, does nothing and return null, unless it was stubbed. Quoting from Mockito docs:

By default, for all methods that return value, mock returns null, an empty collection or appropriate primitive/primitive wrapper value (e.g: 0, false, ... for int/Integer, boolean/Boolean, ...).

This explains your subsequent error: the method was really not invoked on the mock.


It seems what you want here is a spy instead:

You can create spies of real objects. When you use the spy then the real methods are called (unless a method was stubbed).

A note of warning though: since it is the real methods that are getting called, you should not use Mockito.when but prefer Mockito.doReturn(...).when, otherwise the method will be called once for real. If you consider the expression:

Mockito.when(myClass.methodUsedInMethodBeingTested(Matchers.any(MyTypeParam.class))).thenReturn(Collections.<X, Y> emptyMap());
             ^-----------------------------------^
                 this will be invoked by Java

the argument of the method when must be evaluated, but this means the method methodUsedInMethodBeingTested will be invoked. And since we have a spy, it is the real method that will be invoked. So, instead, use:

MyClass spy = Mockito.spy(new MyClass());
Mockito.doReturn(Collections.<X, Y> emptyMap()).when(spy).methodUsedInMethodBeingTested(Matchers.any(MyTypeParam.class));
assertNull(spy.methodToTest(myObject));
Mockito.verify(spy).methodUsedInMethodBeingTested(Matchers.any(MyTypeParam.class));
like image 166
Tunaki Avatar answered Sep 26 '22 08:09

Tunaki