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


  • captcha text