Reputation: 943
I am trying to use Mockito like this :
Mockito.when(Mockito.any(ObjectMapper.class).readValue(Mockito.any(BufferedReader.class),Mockito.any(Class.class))).thenReturn(new Person("1","abc"));
This is from Jackson library .
public <T> T readValue(Reader src, Class<T> valueType)
The reason I am doing it is because the time I reach this point of the code there are a ton of objects which were created. Mocking on every step would take time.
Any reason why I am getting NPE when code reaches this mockito statement?
Stack Trace :
java.lang.NullPointerException
at com.prashant.flax.ShellTest.givenDirectoryHasFiles(ShellTest.java:139)
at com.prashant.flax.ShellTest.testExecute(ShellTest.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
As you can see it is in a given method(this method only has this piece of code) , so I can see while debugging, it reaches over there and crashes.
Upvotes: 16
Views: 25984
Reputation: 791
For me the actual problem was that I was trying to mock a spy. When mocking a spy you have to use the doReturn
or doAnswer
methods. Otherwise the method of the spy will be actually called while trying to mock it and unexpected behavior can happen. E.g. when calling when
with any()
, any()
will just return null
. So it is likely that you will get an NullPointerException
.
Here is a full example that demonstrates the bahavior:
package com.company;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
public class SpyTest {
public class Controller {
public String method(String arg) {
return arg.substring(0, 1);
}
}
@Test
public void withMockTest() {
Controller controllerMocked = mock(Controller.class);
when(controllerMocked.method(anyString())).thenReturn("42");
assertEquals("42", controllerMocked.method("FOO"));
}
@Test(expected = NullPointerException.class)
public void withSpyWhenThenReturnBreakingBecauseMethodToBeMockedIsActuallyBeingCalled() {
Controller controllerSpied = spy(new Controller());
when(controllerSpied.method(any())).thenReturn("42");
}
@Test
public void withSpyDoReturnWhen() {
Controller controllerSpied = spy(new Controller());
doReturn("42").when(controllerSpied).method(any());
assertEquals("42", controllerSpied.method("FOO"));
}
}
Upvotes: 2
Reputation: 6957
To extend on what @jeff-bowman said in his answer, any() returns null, so if you need something that doesn't return null, you can try this:
/**
* never returns null
*/
private inline fun <reified T> any(type: Class<T>): T = Mockito.any(type)
/**
* returns null
*/
private inline fun <reified T> any(): T = Mockito.any<T>()
Upvotes: 2
Reputation: 95704
As Oliver mentioned in the comments, you can't apply when
to happen to all objects. Mockito works via subclassing, so you have to create a mock instance using mock
, spy
, or a @Mock
or @Spy
annotation; customize the behavior; and then install the mock using dependency injection or other similar tricks.
As to why this happens, the return value for any()
actually is null
; matchers like any
are only supposed to be used as arguments to when
and verify
, and Mockito can't produce a specialized instance of Class
that represents "any Class", so Mockito returns a dummy value (null) and stores data on a specialized stack of argument matchers. Though Mockito has better error messages to alert you to this situation, your code NPEs before Mockito can give you a proper exception with usage examples.
For more about matcher return values and the stack, see my other SO answer on "How do Mockito matchers work?".
Upvotes: 14