Mockito Exception - when() requires an argument which has to be a method call on a mock
Asked Answered
K

17

75

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.

Kasten answered 8/2, 2012 at 1:24 Comment(1)
I've the same problem, but I'm using: @Autowired @ReplaceWithMock(beanName="logDao") private LogDao logDaoMock;Profanatory
Z
72

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);
Zhao answered 8/2, 2012 at 6:37 Comment(14)
But I can not debug in that case. do it actually calls that method?Gelb
@eatSleepCode: the REAL method PcUserService.read gets never invoke in this example. Instead an Mockito Mock gets invoked, and this mock return pcUserZhao
yes, I am facing a issue with this, I have a service lets say TestService and it has a method testMethod() and code inside testMethod includes call to another service method for eg. AnotherTestService.getData(). So in my case I am not able to mock AnotherTestService what should I do?Gelb
Why are you not able to replace AnotherTestService with an mock?Zhao
@eatSleepCode: Maybe you should have a look at this answer: https://mcmap.net/q/270518/-mockito-how-to-test-my-dao-with-mockingZhao
@Zhao i have a question if the read method would be static than also do i need to mock the PcUserService class?Selfmortification
@nsu: see #21105903Zhao
Is it correct to mock the class that I want to test in the junit?Singles
When I don't mock it gives error "org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'."Singles
@Hetal Rachh: you should not replace the functionality you want to test by an mock, because then you test the mock. But it is correct to replace some functionality that is used by the function you want to test with an mock. - So if you have an Class with two methods A and B, A contains a lot of stuff you want to test, but A also invoke B and you are not able to execute B in your Test environment, then it is ok to replace B by an mock (but not A)Zhao
@Hetal Rachh: your second commend sounds like a new question. Please raise a new question with more details. So somebody else can also help you to find a good answer.Zhao
Thanks @Ralph. I will raise a new question for my query.Singles
Any idea if someone trying to return a list instead of Object?Gwenny
@Satyaprakash Nayak: when(...).thenReturn(Arrays.asList(element1, element2));Zhao
C
37

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.

Clite answered 4/10, 2016 at 10:32 Comment(3)
The diagnostic is ok, but what is the solution :pEstrus
@Estrus Don't make pcUserService.read final :) Not ideal I know, but there's not a whole lot you can do about it. Mockito can't mock a final method. See https://mcmap.net/q/152896/-final-method-mocking for more detail and possible workaroundsClite
Actually, sometimes you don't mock your own class but some class from an external dependencies. But it's ok I found how to mock final method with mockito #14293363Estrus
H
26

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.

Harvest answered 27/3, 2018 at 8:18 Comment(5)
Thank this worked. But 1 question. How would I solve this issue without making the method and class as openIntuitional
@viper, thanks! I don't use tests now, but suppose, you should use newer version of this library. If I am not mistaken, it supports final methods. Probably you can try to create interfaces or abstract classes.Harvest
I have latest version of mockito but I am still having the issue. What are the drawbacks of using an open modifier?Intuitional
@viper, see #14293363, github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2, github.com/powermock/powermock/wiki/mockito.Harvest
@viper, it means that descendants of your open class may change a behavior in a way you didn't expect. Overriden methods can access those collections you didn't want to access. Or even change collections, objects. See also quora.com/What-are-all-the-advantages-of-inheritance-in-Java, quora.com/What-are-the-disadvantages-of-inheritance-in-Java.Harvest
V
9

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 })

Vanlandingham answered 28/9, 2017 at 21:46 Comment(1)
Thanks, I thought I had, but I actually added the interface to the @preparefortest list, not the class, this answer made me double check there.Fitzhugh
S
5

In my case it was solved by injecting @MockBean.

For ex.

@MockBean
StateRepository mockStateRepository;
Servomechanical answered 18/5, 2020 at 8:39 Comment(0)
A
4

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.

Audit answered 10/1, 2018 at 10:49 Comment(0)
B
4

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"))

Berber answered 22/11, 2021 at 17:18 Comment(0)
N
3

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.

Nalepka answered 11/9, 2018 at 7:58 Comment(0)
F
2

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.

Fults answered 15/12, 2019 at 6:42 Comment(0)
D
1

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.

Dielle answered 17/4, 2020 at 18:40 Comment(0)
P
1

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:

https://mkyong.com/spring-boot/mockito-when-requires-an-argument-which-has-to-be-a-method-call-on-a-mock/

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.

Pepe answered 28/4, 2022 at 14:30 Comment(0)
A
1

I have faced a similar issue. You can simply use the “spy” annotation on the “pcUserService” bean, if you cannot mock the “pcUserService” bean (e.g. when the “pcUserService” bean itself is under test and has @InjectMocks annotation). Briefly, “spy” means you mock the bean partially.

The Mockito – when() requires an argument which has to be ‘a method call on a mock’ is so great and makes the point in a nutshell with a simple and useful example.

Austreng answered 29/10, 2023 at 9:10 Comment(0)
E
0

If you use KOIN, include in the gradle's dependencies:

dependencies {
    ...
    testImplementation "org.koin:koin-test:2.0.0"
}
Endpaper answered 5/4, 2021 at 11:49 Comment(0)
S
0

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.

Schlueter answered 11/4, 2021 at 18:56 Comment(0)
T
0

I faced same issue and it was because the mocked object is defined as @Beanand the overriden @Bean in the test was not working because of a missing spring property value

@Bean
@Primary
public JwtTokenUtil jwtTokenUtil() {
    return Mockito.mock(JwtTokenUtil.class);
}

@Autowired
private JwtTokenUtil jwtTokenUtil;

when(jwtTokenUtil.validateToken(jwtToken)).thenReturn(true);

Fix

spring.main.allow-bean-definition-overriding=true in application-test.properties

Twerp answered 5/10, 2022 at 4:43 Comment(0)
F
0

In my case, I had to attach the attach the Mockito extension to the Class

@ExtendWith(MockitoExtension.class)
class pcUserService{
 ... 
}
Freeloader answered 26/11, 2023 at 19:8 Comment(0)
C
-1

if anything above answers your case, then check that you did missed the @Test annotation for your test method.

@Test
public void my_test_method(){
}

just quoting, as this was my case. just missed the annotation.

Corcyra answered 24/1, 2023 at 6:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.