I am getting null pointer exception while I am trying to mock
@WebMvcTest(IMnJobManager.class)
public class CMnJobManagerTest {
@Autowired
private MockMvc mockmvc;
@Test
public void testExample()throws Exception{
IMnAllWorkFlows allWorkFlows = Mockito.mock(IMnAllWorkFlows.class);
Mockito.doAnswer(
invocation -> {
return Arrays.asList( "modn-ops");
}).when(allWorkFlows).getAllTenants();
mockmvc.perform(get("/v1/tenant"))
.andExpect(status().isOk())
.andExpect(content().string("modn-ops"))
.andDo(print());
}
}
I am getting following error:
java.lang.NullPointerException
at com.test.manager.CMnJobManagerTest.testExample(CMnJobManagerTest.java:32)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
My interface implementation class looks like below:
@RestController
public class CMnJobManager implements IMnJobManager {
@Autowired
public CMnJobManager(IMnAllWorkFlows allWorkFlows, IMnWorkflowService workflowService,
IMnTemporalServiceClient temporalServiceClient, IMnWorkflowHistoryService workflowHistoryService,
IMnSearchAttributeService searchAttributeService, IMnS3Tenant s3Tenant) {
this.allWorkFlows = allWorkFlows;
this.workflowService = workflowService;
this.searchAttributeService = searchAttributeService;
this.workflowHistoryService = workflowHistoryService;
this.temporalServiceClient = temporalServiceClient;
this.s3Tenant = s3Tenant;
}
.
.
.
@Autowired
private HttpServletRequest request;
@Autowired
private CMnCustomMetricService customMetricService;
}
The interface has many methods but I am trying to mock only one. The rest call, will make a call to the IMnJobManager interface and hence I have mocked it.
Error says the issue is at mockMvc.perform(...) and hence the NullPointerException.
When I remove Autowired from MockMvc, and add mockMvc = MockMvcBuilders.standaloneSetup(allWorkFlows).build();, it gives 404.
Any idea what might be wrong here?
There seems to be a lot of confusion what the annotations do and how to correctly use Mockito to set up mock objects/test doubles.
To get started, I recommend to read the following posts:
Let's look at some of the mistakes first and in the end come back to write a working test.
The
valueproperty of the@WebMvcTestannotation specifies the Controllers to load in the Spring context.IMnJobManageris not a controller, but your job manager interface. You want to passCMnJobManager.classinstead.@WebMvcTestonly loads the web context of your application (such as the controllers). From the JavaDoc of the annotation:So none of your Service beans will be loaded.
Further down in the same JavaDoc:
What does that mean?
@WebMvcTest(IMnJobManager.class)will not create any endpoints, becauseIMnJobManageris not a controller and does not define any request mappings. This line explicitly tells Spring to not load your real controller. Trying to request any endpoint (withmockmvc.perform(get(…))will result in a 404/NOT_FOUND.This code creates a new Mockito mock object, stubs a method on it, and then … does nothing with it. The instance is local to the method and does not exist outside of it, nor is it accessible from the outside. It is not registered in the application context and it cannot be used by your controller. (Now's a good time to read the linked Stackoverflow post a second time).
How do we make the instance available as collaborator to our controller? We do what the JavaDoc of the annotation tells us: define it as
@MockBean:And then stub the method in the setup/
@BeforeEachmethod. In simple tests such as in the question, the stubbing could be configured in the test itself too.Fixing all of the above should:
Here's a simple, yet full, demo project (i.e. a Minimal, Reproducible Example with all classes required to compile and execute the code) which shows that the solution outlined above does indeed work:
DemoService.java:DemoController.java:WebApplicationTest.java: