DEV Community

Cover image for How to unit test a custom actuator endpoint
Michèle for opt-nc

Posted on • Edited on

How to unit test a custom actuator endpoint

Previously, I posted on "How to create a custom endpoint to monitor Jira", this is the second part, showing how to unit test this endpoint with SpringBoot MockMvc, Mokito and PowerMokito.

Here the list of dependencies required :

 implementation 'junit:junit:4.12' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' exclude group: "com.vaadin.external.google", module:"android-json" } testImplementation group: 'com.konghq', name: 'unirest-mocks', version: '3.11.06' testImplementation group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.9' testImplementation group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.9' 
Enter fullscreen mode Exit fullscreen mode

We first need a class that load our configuration class used by the JiraConnectorService.

@TestConfiguration public class TestConfig { @Bean public JiraConfig getJiraConfig(){ return new JiraConfig(); } } 
Enter fullscreen mode Exit fullscreen mode

Test the service to be sure it returns the good data according to the Jira endpoint response.
To do so, we need to mock the Unirest.get() call and response.

@RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(SpringRunner.class) @PrepareForTest(Unirest.class) @Import({TestConfig.class}) @PowerMockIgnore({"javax.*.*", "com.sun.*", "org.xml.*"}) @SpringBootTest public class JiraConnectorServiceTest { @Mock private GetRequest getRequest; @Autowired JiraConnectorService jiraConnectorService; @Autowired JiraConfig jiraConfig; @Test public void getResponseTimeTest() throws Exception { JsonNode json = new JsonNode("{\"result\":10}"); HttpResponse<JsonNode> mockResponse = mock(HttpResponse.class); when(mockResponse.getStatus()).thenReturn(200); when(mockResponse.getBody()).thenReturn(json); String mySelfEndPointUrl = jiraConfig.getHost() + jiraConfig.getApiPath() + JiraConnectorService.JIRA_MYSELF_ENDPOINT; PowerMockito.mockStatic(Unirest.class); when(Unirest.get(mySelfEndPointUrl)).thenReturn(getRequest); when(getRequest.header(JiraConnectorService.HEADER_ACCEPT, JiraConnectorService.HEADER_APP_JSON)).thenReturn(getRequest); when(getRequest.basicAuth(jiraConfig.getUser(), jiraConfig.getPassword())).thenReturn(getRequest); when(getRequest.asJson()).thenReturn(mockResponse); ResponseTimeData data = jiraConnectorService.getResponseTime(); Assert.assertEquals(HttpStatus.OK.value(), data.getHttpStatusCode()); Assert.assertTrue(data.getTime() > 0); } 
Enter fullscreen mode Exit fullscreen mode

We have to use PowerMockito and @RunWith(PowerMockRunner.class) annotation to mock the static method Unirest.get(..).

We can only use one @RunWith annotation, that's why we add @PowerMockRunnerDelegate(SpringRunner.class) to load the Spring context.

Then test the endpoint :

 @RunWith(SpringRunner.class) @Import({TestConfig.class}) @AutoConfigureMockMvc @SpringBootTest public class RestJiraEndPointTest { private static final String ACTUATOR_URI = "/management"; @MockBean private JiraConnectorService jiraConnectorService; @Autowired private MockMvc mockMvc; @Test public void healthDtl_DOWN() throws Exception { ResponseTimeData data = new ResponseTimeData(); data.setTime(-1); data.setHttpStatusCode(HttpStatus.SERVICE_UNAVAILABLE.value()); data.setMessage("Service unavailable"); Mockito.when(jiraConnectorService.getResponseTime()).thenReturn(data); RequestBuilder requestBuilder = MockMvcRequestBuilders.get(ACTUATOR_URI + "/jira/healthDtl") .accept(MediaType.APPLICATION_JSON); this.mockMvc.perform(requestBuilder) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.status").value("DOWN")); } @Test public void healthDtl_UP() throws Exception { ResponseTimeData data = new ResponseTimeData(); data.setTime(235L); data.setHttpStatusCode(HttpStatus.OK.value()); data.setMessage("Ok"); Mockito.when(jiraConnectorService.getResponseTime()).thenReturn(data); RequestBuilder requestBuilder = MockMvcRequestBuilders.get(ACTUATOR_URI + "/jira/healthDtl") .accept(MediaType.APPLICATION_JSON); this.mockMvc.perform(requestBuilder) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.status").value("UP")) .andExpect(MockMvcResultMatchers.jsonPath("$.responseTimeMs").value("235")); } } 
Enter fullscreen mode Exit fullscreen mode

I first tried to use @WebMvcTest(RestJiraEndPoint.class) instead of @SpringBootTest but without success. Spring seems to not recognized @RestControllerEndpoint as a rest controller. So, you have to use @SpringBootTest and @AutoConfigureMockMvc.

Top comments (1)

Collapse
 
bsl profile image
BELAGGOUN

Hello , thank you for this tutorial.
I have created a service that implements HealthIndicator Interface , and based on the health components (HealthIndicators Beans) status I perform some business logic.
ex: if diskSpaceHealthIndicator.getStatus()=="UP" I perform Action1 else Action2.
I'm having hard time on how to mock the HealthIndicator beans , I'm using @MockBean PingHealthContributor pingHealthContributor;
but when I do :
when(when(((HealthIndicator)
(pingHealthContributor)).health().getStatus()).thenReturn(health.getStatus());
the getStatus is returning null pointer exception.
Please let me know if you have any Idea on how to mock the actuator health beans .
Thank you .