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:
// ...
<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¶
// ...
@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¶
// ...
@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));
}
}
// ...