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 .