Show List
Testing Spring Boot Application
In this example we will be testing the Spring Boot application using JUnit, SpringBootTest, MockMvc and WebMvcTest. For this testing we do not have to add any new dependencies as we will be using test support provided by spring framework.
Here is the project structure. We are going to use the rest API from the previous chapter . You can download the source code from there to code along:
build.gradle
Here is the build.gradle for the project. Gradle test task has been configured to use JUnit platform.
plugins {
id 'java'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa:2.7.3'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.4'
implementation 'org.springframework.boot:spring-boot-starter-web:2.7.0'
runtimeOnly 'com.h2database:h2:2.1.214'
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.7.0'
}
test {
useJUnitPlatform()
}
@SpringBootTest
@SpringBootTest annotation loads the complete Spring Application Context. Here is a simple test class to verify that the cotroller was loaded successfully.
SmokeTest.java
package com.example.demo;
import static org.assertj.core.api.Assertions.assertThat;
import com.example.demo.controller.StudentController;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class SmokeTest {
@Autowired
private StudentController controller;
@Test
public void contextLoads() throws Exception {
assertThat(controller).isNotNull();
}
}
You can run it using command ./gradlew test (or gradlew.bat test from Windows), or run the test Gradle task or from your IDE.
The test report can be found under \build\reports\tests\test\index.html
Using Random Port for Test
To ensure that the test application run does not conflict with live application, we can start the application on a random port and test the end points. Spring boot also provides TestRestTemplate automatically to test the API.
RESTCallTest.java
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.beans.factory.annotation.Value;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RESTCallTest {
@Value(value="${local.server.port}")
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void shouldReturnStudent() throws Exception {
assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/student/1",
String.class)).contains("Ana");
}
}
Rest report after running the test (\build\reports\tests\test\index.html):
@WebMvcTest
@SpringBootTest used in the above examples starts the full application context and injects all the beans which can be slow.
@WebMvcTest on the other hand is for testing the controller layer so only instantiates the provided controller. If there are additional dependencies for the test, we have to provide them using the Mock objects.
MockMvc encapsulates application bean and makes them available for the testing.
Here is an example:
WebMvcTestWebLayerWithoutServerStart.java
package com.example.demo;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.example.demo.controller.StudentController;
import com.example.demo.dao.StudentRepo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
@WebMvcTest(StudentController.class) //Instantiate only StudentController
public class WebMvcTestWebLayerWithoutServerStart {
@Autowired
private MockMvc mockMvc;
@MockBean
private StudentRepo repo;
@Test
public void shouldReturnStudent() throws Exception {
this.mockMvc.perform(get("/dummy")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello")));
}
}
@AutoConfigureMockMvc
It is a subset of @WebMvcTest and is used for auto configuration of MockMvc.
MockMVCTestWithoutServerStart.java
package com.example.demo;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
@SpringBootTest
@AutoConfigureMockMvc
public class MockMVCTestWithoutServerStart {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnStudent() throws Exception {
this.mockMvc.perform(get("/student/1")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Ana")));
}
}
When all above test classes are executed using gradle test
PS C:\Users\mail2\Downloads\Testing Spring Boot API with JUnit and MockMVC> gradle test > Task :test 2022-12-21 11:46:38.883 INFO 3424 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-12-21 11:46:38.883 INFO 3424 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down' Hibernate: drop table if exists student CASCADE 2022-12-21 11:46:38.886 INFO 3424 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-12-21 11:46:38.887 INFO 3424 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. 2022-12-21 11:46:39.158 INFO 3424 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-12-21 11:46:39.159 INFO 3424 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down Hibernate: drop table if exists student CASCADE 2022-12-21 11:46:39.161 INFO 3424 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Shutdown initiated... 2022-12-21 11:46:39.164 INFO 3424 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-2 - Shutdown completed. 2022-12-21 11:46:39.167 INFO 3424 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-12-21 11:46:39.167 INFO 3424 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down' Hibernate: drop table if exists student CASCADE 2022-12-21 11:46:39.170 INFO 3424 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-3 - Shutdown initiated... 2022-12-21 11:46:39.172 INFO 3424 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-3 - Shutdown completed. BUILD SUCCESSFUL in 15s 4 actionable tasks: 3 executed, 1 up-to-date
The output report at \build\reports\tests\test\index.html
Source Code:
https://github.com/it-code-lab/Testing-Spring-Boot-API-with-JUnit-and-MockMVC
Leave a Comment