Skip to content

Testing

Estimated time to read: 3 minutes

Overview

Testing gives you the confidence that the application is working when changes are introduced into the code.

Dependencies

To include Testing in a project, the following dependencies are required:

pom.xml
// ...
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starer-test</artifactId>
    <version>X.y.z</version>
</dependency>

spring-boot-starer-test imports both Spring Boot test modules as well as JUnit, AssertJ, Hamcrest and an handful of other libraries.

Unit Testing

For more information on JUnit, Mockito and TDD, see TAVISTOFIXLINK

JUnit, Mockito and Spring Test are often referred to as MockMvc when used with Spring.

Spring also includes the @MockBean annotation which works alongside Mockito.

@WebMvcTest

The @WebMvcTest annotation is used for controller layer unit testing and is often used to test one controller class at a time, and works in combination with Mockito to mock the dependencies.

@WebMvcTest scans for classes annotated with @Controllers, including @RestControllers, it does not load the full application context.

If the controller has dependencies on other beans, for example a bean from the service layer, the test will not run until the bean is loaded or a mock is provided for it. Typically, beans are created manually by mocking the objects.

@WebMvcTest speeds up testing by only loading a small portion of the application for unit testing.

Example

TzaControllerUnitTest.java
// ...

@RunWith(SpringRunner.class) // The `@RunWith` annotation defines the runner class to be used to run test cases. SpringRunner is used since Spring is being used to build the application.
@WebMvcTest(TzaController.class) // The `@WebMvcTest` annotation defines the class of the controller to be tested. In this case, this will start the web application context; the embedded servlet container is not used. 
public class TzaControllerUnitTest {

    @Autowired
    private MockMvc mockMvc; // MockMvc is used to test MVC controllers. It also helps with processing HTTP responses, by providing `expectation` methods

    @MockBean // The `@MockBean` annotation creates a Mockito mock of the services which are dependencies for the controller.
    ApplicationService applicationService;

    @MockBEan
    TicketService ticketService;

    @Test 
    public void getAllApplications() throws Exception {
        mockMvc.perform(get("/tza/applications/")) // Use the perform method of MockMvc, which simulates making a HTTP request to a controller and the given mapping
               .andExpect(status().isOk()) // Expects a 200 Status OK HTTP Status
               .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)) // Expects the returned media type to be UTF8 formatted JSON
               .andExpect(content().json("[]")); // Expects the content of the JSON to be empty

        verify(applicationService, times(1)).listApplications(); // The verify method is used to ensure how many times a mock method / service has been called.
    }
}
// ...

Integration Tests

Integration testing allows for testing of the entire application and its layers, not just individual units. This can be done without deployment of the entire application.

The @SpringBootTest annotation is used for integration testing and is chosen over @WebMvcTest as @SpringBootTest starts the full application context, including the server, and does not customize component scanning at all.

@SpringBootTest locates the main configuration class, annotated with @SpringBootApplication, and use that to start a Spring ApplicationContext simulating a client call.

Example

TzaControllerIntegrationTest.java
// ...

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // The `@SpringBootTest` annotation. In this instance, the parameters define a random port to be used.
@AutoConfigureMockMvc // The `@AutoConfigureMockMvc` annotation simulates calling the code from the client as if it were processing a real HTTP request
public class TzaControllerIntegrationTest {

    @LocalServerPort
    private int port;

    @Autowired
    private TestRestTemplate restTemplate; // TestRestTemplate allows consumption of a REST API from the test case. Spring Boot provides this TestRestTemplate automatically when it is annotated with `@Autowired`

    @Test
    public void getAllApplications() throws Exception {
        ResponseEntity<List> response = this.restTemplate.getForEntity("http://localhost:" + port + "/tza/applications/" , List.class);// The getForEntity method of the restTemplate field is used. This invokes a GET request on an API, the response is then converted and stored in the response object of type ResponseEntity

        assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
    }

    @Test
    public void getAllTickets() throws Exception {
        ResponseEntity<List> response = this.restTemplate.getForEntity("http://localhost:" + port + "/tza/tickets/", List.class)

        assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
    }
}

// ...