How to unit test a custom actuator endpoint

Michèle - Jan 4 '21 - - Dev Community

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .