Mockito Exception - when() requires an argument which has to be a method call on a mock
JavaControllerMockitoSpring TestJava Problem Overview
I have a very simple test case that is using Mockito and Spring Test framework. When I do
when(pcUserService.read("1")).thenReturn(pcUser);
I get this exception.
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
at com.project.cleaner.controller.test.PcUserControllerTest.shouldGetPcUser(PcUserControllerTest.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
I have tried with different methods but keep on getting this error message. I am using Spring 3.1.0.RELEASE with Mockito. Please share and guide me in the right direction.
Java Solutions
Solution 1 - Java
You need to create a MOCK of pcUserService first, and then use that mock.
PcUserService mock = org.mockito.Mockito.mock(PcUserService.class);
when(mock.read("1")).thenReturn(pcUser);
Solution 2 - Java
In case others hit this issue....
It could also be the case that the method you are trying to mock out,pcUserService.read
, is declared as a final
method. From what I've noticed this appears to cause issues with Mockito.
Solution 3 - Java
If you use Kotlin
, you should know that methods are final
by default. So write open fun
instead of fun
. Thanks to @djkelly99 for a tip.
Solution 4 - Java
Another solution to this issue might be that in case of a test class that is using PowerMockRunner
, you might have to add the class that you are mocking to the list, in @PrepareForTest
annotation.
For instance -
@PrepareForTest({ PcUserService.class })
Solution 5 - Java
In my case it was solved by injecting @MockBean
.
For ex.
@MockBean
StateRepository mockStateRepository;
Solution 6 - Java
There's another possible reason for such error - sometimes IDE prefers to statically import Mockito.when() from another package:
import static io.codearte.catchexception.shade.mockito.Mockito.when;
vs
import static org.mockito.Mockito.when; //should normally use this one
The thing is 'when' from io.codearte package is compliant with org.mockito.Mockito.any() on compilation level, but fails during runtime with that exact same error message.
Solution 7 - Java
I had the same issue, the method that I was trying to mock it was a final method. I removed the modifier and it worked fine.
Solution 8 - Java
For the help of others who stuck with the same problem;
The method you are trying to mock , pcUserService.read, is declared as a final method. Static methods appears to cause issues with Mockito.
Solution 9 - Java
Basically You need to use the PowerMockito.mockStatic to enable static mocking for all static methods of a class. This means make it possible to stub them using the when-thenReturn syntax.
For example:
PowerMockito.mockStatic(TestClass.class); when(TestClass.getString()).thenReturn("HelloWorld!");
Note: you have to add @PrepareForTest({ TestClass.class })
to your unit test class.
Solution 10 - Java
If you get this exception when using MockedStatic
or Mockito.mockStatic
, it can also mean that you are mixing matchers and literals in the call to the static method.
Try changing any mixes like YourClass.staticMethod(any(), "literal")
to YourClass.staticMethod(any(), eq("literal"))
Solution 11 - Java
If you use KOIN, include in the gradle's dependencies:
dependencies {
...
testImplementation "org.koin:koin-test:2.0.0"
}
Solution 12 - Java
I faced similar issue when mocking static method of anotherClass called inside testing a method of someClass. In that case, we need to add @PrepareForTest({anotherClass.class, someClass.class}) both the class having the static method and caller class.
Solution 13 - Java
When I got this exception, I was using @InjectMocks on the class that I needed to have the @Mock objects injected into (via constructor injection).
AFter much searching, I finally stumbled across this article:
The key part to take away from it is (from the article):
> When Mockito see this @InjectMocks, it doesn’t mock it, it just > creates a normal instance, so the when() will be failed.
So this make this exception message I was getting
> when() requires an argument which has to be 'a method call on a mock'.
make sense now; you aren't using when on an actual mock but an actual instance.
The link also provides the solution to the problem:
> To solve it, annotate @Spy to mock it partially.
On top of @InjectMocks, put @Spy.
As a side note, if you try to make it a Mock by putting @Mock on top of @InjectMocks, you will get exception:
> org.mockito.exceptions.base.MockitoException: This combination of > annotations is not permitted on a single field: @Mock and @InjectMocks
Using @Spy on top of @InjectMocks solved the problem for me.