46

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.

Killer
  • 582
  • 1
  • 7
  • 24
jsf
  • 2,511
  • 8
  • 28
  • 33

11 Answers11

55

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);
Ralph
  • 111,219
  • 48
  • 270
  • 362
  • But I can not debug in that case. do it actually calls that method? – eatSleepCode Jun 10 '14 at 13:13
  • @eatSleepCode: the REAL method `PcUserService.read` gets never invoke in this example. Instead an Mockito Mock gets invoked, and this mock return `pcUser` – Ralph Jun 10 '14 at 13:43
  • 1
    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? – eatSleepCode Jun 11 '14 at 04:52
  • Why are you not able to replace `AnotherTestService` with an mock? – Ralph Jun 11 '14 at 05:21
  • @eatSleepCode: Maybe you should have a look at this answer: http://stackoverflow.com/a/20856647/280244 – Ralph Jun 11 '14 at 05:33
  • @Ralph i have a question if the read method would be static than also do i need to mock the PcUserService class? – u12345 May 12 '15 at 10:24
  • @nsu: see http://stackoverflow.com/questions/21105403/mocking-static-methods-with-mockito – Ralph May 12 '15 at 11:03
  • Is it correct to mock the class that I want to test in the junit? – Hetal Rachh Sep 18 '19 at 06:08
  • 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'." – Hetal Rachh Sep 18 '19 at 06:14
  • @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) – Ralph Sep 18 '19 at 10:37
  • @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. – Ralph Sep 18 '19 at 10:39
  • Thanks @Ralph. I will raise a new question for my query. – Hetal Rachh Sep 19 '19 at 05:51
  • Any idea if someone trying to return a list instead of Object? – Satyaprakash Nayak May 21 '21 at 04:59
  • @Satyaprakash Nayak: `when(...).thenReturn(Arrays.asList(element1, element2));` – Ralph May 23 '21 at 17:38
28

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.

djkelly99
  • 488
  • 4
  • 7
  • The diagnostic is ok, but what is the solution :p – amdev Jul 22 '18 at 07:07
  • @amdev 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://stackoverflow.com/questions/3793791/final-method-mocking for more detail and possible workarounds – djkelly99 Jul 24 '18 at 21:37
  • 1
    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 https://stackoverflow.com/questions/14292863/how-to-mock-a-final-class-with-mockito/14307615 – amdev Jul 25 '18 at 07:32
14

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.

CoolMind
  • 16,738
  • 10
  • 131
  • 165
  • 1
    Thank this worked. But 1 question. How would I solve this issue without making the method and class as `open` – viper Oct 02 '19 at 05:27
  • 1
    @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. – CoolMind Oct 02 '19 at 07:09
  • I have latest version of `mockito` but I am still having the issue. What are the drawbacks of using an `open` modifier? – viper Oct 02 '19 at 07:12
  • @viper, see https://stackoverflow.com/questions/14292863/how-to-mock-a-final-class-with-mockito, https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2, https://github.com/powermock/powermock/wiki/mockito. – CoolMind Oct 02 '19 at 07:16
  • @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 https://www.quora.com/What-are-all-the-advantages-of-inheritance-in-Java, https://www.quora.com/What-are-the-disadvantages-of-inheritance-in-Java. – CoolMind Oct 02 '19 at 07:27
7

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

Saran
  • 871
  • 7
  • 10
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.

3

In my case it was solved by injecting @MockBean.

For ex.

@MockBean
StateRepository mockStateRepository;
Ninad Pingale
  • 5,634
  • 4
  • 24
  • 45
2

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.

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.

pasindupa
  • 401
  • 5
  • 8
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.

ajain
  • 212
  • 2
  • 6
0

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

dependencies {
    ...
    testImplementation "org.koin:koin-test:2.0.0"
}
J. Soares
  • 49
  • 4
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.