- Spring Boot 教程
- Spring Boot - 首頁
- Spring Boot - 簡介
- Spring Boot - 快速入門
- Spring Boot - 引導
- Spring Tool Suite
- Spring Boot - Tomcat 部署
- Spring Boot - 構建系統
- Spring Boot - 程式碼結構
- Spring Bean & 依賴注入
- Spring Boot - 執行器
- Spring Boot - 啟動器
- Spring Boot - 應用程式屬性
- Spring Boot - 配置
- Spring Boot - 註解
- Spring Boot - 日誌
- 構建 RESTful Web 服務
- Spring Boot - 異常處理
- Spring Boot - 攔截器
- Spring Boot - Servlet 過濾器
- Spring Boot - Tomcat 埠號
- Spring Boot - Rest 模板
- Spring Boot - 檔案處理
- Spring Boot - 服務元件
- Spring Boot - Thymeleaf
- 使用 RESTful Web 服務
- Spring Boot - CORS 支援
- Spring Boot - 國際化
- Spring Boot - 排程
- Spring Boot - 啟用 HTTPS
- Spring Boot - Eureka 伺服器
- 使用 Eureka 註冊服務
- 閘道器代理伺服器和路由
- Spring Cloud 配置伺服器
- Spring Cloud 配置客戶端
- Spring Boot - Actuator
- Spring Boot - Admin 伺服器
- Spring Boot - Admin 客戶端
- Spring Boot - 啟用 Swagger2
- Spring Boot - 使用 SpringDoc OpenAPI
- Spring Boot - 建立 Docker 映象
- 跟蹤微服務日誌
- Spring Boot - Flyway 資料庫
- Spring Boot - 傳送電子郵件
- Spring Boot - Hystrix
- Spring Boot - Web Socket
- Spring Boot - 批處理服務
- Spring Boot - Apache Kafka
- Spring Boot - Twilio
- Spring Boot - 單元測試用例
- Rest 控制器單元測試
- Spring Boot - 資料庫處理
- 保護 Web 應用程式
- Spring Boot - 帶 JWT 的 OAuth2
- Spring Boot - Google Cloud Platform
- Spring Boot - Google OAuth2 登入
- Spring Boot 資源
- Spring Boot - 快速指南
- Spring Boot - 有用資源
- Spring Boot - 討論
Spring Boot - Rest 控制器單元測試
Spring Boot 提供了一種簡單的方法來為 Rest Controller 檔案編寫單元測試。藉助 SpringJUnit4ClassRunner 和 MockMvc,我們可以建立一個 Web 應用程式上下文來為 Rest Controller 檔案編寫單元測試。
單元測試應該寫在 src/test/java 目錄下,編寫測試的類路徑資源應該放在 src/test/resources 目錄下。
為了編寫單元測試,我們需要在構建配置檔案中新增 Spring Boot Starter Test 依賴項,如下所示。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
Gradle 使用者可以在其 build.gradle 檔案中新增以下依賴項。
testCompile('org.springframework.boot:spring-boot-starter-test')
在編寫測試用例之前,我們應該首先構建 RESTful Web 服務。有關構建 RESTful Web 服務的更多資訊,請參閱 構建 RESTful Web 服務 章節。
為 REST 控制器編寫單元測試
在本節中,讓我們看看如何為 REST 控制器編寫單元測試。
首先,我們需要建立一個抽象類檔案,用於使用 MockMvc 建立 Web 應用程式上下文,並定義 mapToJson() 和 mapFromJson() 方法,以將 Java 物件轉換為 JSON 字串,並將 JSON 字串轉換為 Java 物件。
AbstractTest.java
package com.tutorialspoint.demo;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@SpringBootTest(classes = DemoApplication.class)
@WebAppConfiguration
public abstract class AbstractTest {
protected MockMvc mvc;
@Autowired
WebApplicationContext webApplicationContext;
protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected String mapToJson(Object obj) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(obj);
}
protected <T> T mapFromJson(String json, Class<T> clazz)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, clazz);
}
}
接下來,編寫一個擴充套件 AbstractTest 類併為每個方法(如 GET、POST、PUT 和 DELETE)編寫單元測試的類檔案。
GET API 測試用例的程式碼如下所示。此 API 用於檢視產品列表。
@Test
public void getProductsList() throws Exception {
String uri = "/products";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(uri)
.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
Product[] productlist = super.mapFromJson(content, Product[].class);
assertTrue(productlist.length > 0);
}
POST API 測試用例的程式碼如下所示。此 API 用於建立產品。
@Test
public void createProduct() throws Exception {
String uri = "/products";
Product product = new Product();
product.setId("3");
product.setName("Ginger");
String inputJson = super.mapToJson(product);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
.contentType(MediaType.APPLICATION_JSON_VALUE).content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(201, status);
String content = mvcResult.getResponse().getContentAsString();
assertEquals(content, "Product is created successfully");
}
PUT API 測試用例的程式碼如下所示。此 API 用於更新現有產品。
@Test
public void updateProduct() throws Exception {
String uri = "/products/2";
Product product = new Product();
product.setName("Lemon");
String inputJson = super.mapToJson(product);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.put(uri)
.contentType(MediaType.APPLICATION_JSON_VALUE).content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
assertEquals(content, "Product is updated successsfully");
}
Delete API 測試用例的程式碼如下所示。此 API 將刪除現有產品。
@Test
public void deleteProduct() throws Exception {
String uri = "/products/2";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.delete(uri)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
assertEquals(content, "Product is deleted successsfully");
}
完整的 Controller 測試類檔案如下所示:
ProductServiceControllerTest.java
package com.tutorialspoint.demo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import com.tutorialspoint.demo.model.Product;
public class ProductServiceControllerTest extends AbstractTest {
@Override
@BeforeEach
public void setUp() {
super.setUp();
}
@Test
public void getProductsList() throws Exception {
String uri = "/products";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(uri)
.accept(MediaType.APPLICATION_JSON_VALUE)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
Product[] productlist = super.mapFromJson(content, Product[].class);
assertTrue(productlist.length > 0);
}
@Test
public void createProduct() throws Exception {
String uri = "/products";
Product product = new Product();
product.setId("3");
product.setName("Ginger");
String inputJson = super.mapToJson(product);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.post(uri)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(201, status);
String content = mvcResult.getResponse().getContentAsString();
assertEquals(content, "Product is created successfully");
}
@Test
public void updateProduct() throws Exception {
String uri = "/products/2";
Product product = new Product();
product.setName("Lemon");
String inputJson = super.mapToJson(product);
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.put(uri)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(inputJson)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
assertEquals(content, "Product is updated successsfully");
}
@Test
public void deleteProduct() throws Exception {
String uri = "/products/2";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.delete(uri)).andReturn();
int status = mvcResult.getResponse().getStatus();
assertEquals(200, status);
String content = mvcResult.getResponse().getContentAsString();
assertEquals(content, "Product is deleted successsfully");
}
}
完整的構建配置檔案 Maven 構建 – pom.xml 的程式碼如下所示:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tutorialspoint</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
編譯和執行
您可以建立一個可執行的 JAR 檔案,並使用以下 Maven 或 Gradle 命令執行 Spring Boot 應用程式:
對於 Maven,您可以使用以下命令:
mvn clean install
現在,您可以在控制檯視窗中看到測試結果。
[INFO] Scanning for projects... [INFO] [INFO] [1m----------------------< [0;36mcom.tutorialspoint:demo[0;1m >-----------------------[m [INFO] [1mBuilding demo 0.0.1-SNAPSHOT[m [INFO] from pom.xml [INFO] [1m--------------------------------[ jar ]---------------------------------[m ... [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.tutorialspoint.demo.[1mDemoApplicationTests[m [2024-09-25T15:56:58Z] [org.springframework.test.context.support.AnnotationConfigContextLoaderUtils] [main] [83] [INFO ] Could not detect default configuration classes for test class [com.tutorialspoint.demo.DemoApplicationTests]: DemoApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration. [2024-09-25T15:56:58Z] [org.springframework.boot.test.context.SpringBootTestContextBootstrapper] [main] [234] [INFO ] Found @SpringBootConfiguration com.tutorialspoint.demo.DemoApplication for test class com.tutorialspoint.demo.DemoApplicationTests . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.3.3) [2024-09-25T15:56:59Z] [org.springframework.boot.StartupInfoLogger] [main] [50] [INFO ] Starting DemoApplicationTests using Java 21.0.3 with PID 7200 (started by Tutorialspoint in E:\Dev\demo) [2024-09-25T15:56:59Z] [org.springframework.boot.SpringApplication] [main] [654] [INFO ] No active profile set, falling back to 1 default profile: "default" ... [INFO] [1;32mTests run: [0;1;32m1[m, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.972 s -- in com.tutorialspoint.demo.[1mDemoApplicationTests[m [INFO] Running com.tutorialspoint.demo.[1mProductServiceControllerTest[m . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.3.3) [2024-09-25T15:57:04Z] [org.springframework.boot.StartupInfoLogger] [main] [50] [INFO ] Starting ProductServiceControllerTest using Java 21.0.3 with PID 7200 (started by Tutorialspoint in E:\Dev\demo) [2024-09-25T15:57:04Z] [org.springframework.boot.SpringApplication] [main] [654] [INFO ] No active profile set, falling back to 1 default profile: "default" [2024-09-25T15:57:04Z] [org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping] [main] [59] [INFO ] Adding welcome page template: index [2024-09-25T15:57:04Z] [org.springframework.boot.StartupInfoLogger] [main] [56] [INFO ] Started ProductServiceControllerTest in 0.79 seconds (process running for 7.632) [2024-09-25T15:57:04Z] [org.springframework.mock.web.MockServletContext] [main] [437] [INFO ] Initializing Spring TestDispatcherServlet '' [2024-09-25T15:57:04Z] [org.springframework.web.servlet.FrameworkServlet] [main] [532] [INFO ] Initializing Servlet '' [2024-09-25T15:57:04Z] [org.springframework.web.servlet.FrameworkServlet] [main] [554] [INFO ] Completed initialization in 1 ms ... [INFO] [1;32mTests run: [0;1;32m4[m, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.108 s -- in com.tutorialspoint.demo.[1mProductServiceControllerTest[m [INFO] [INFO] Results: [INFO] [INFO] [1;32mTests run: 5, Failures: 0, Errors: 0, Skipped: 0[m [INFO] [INFO] [INFO] [1m--- [0;32mjar:3.4.2:jar[m [1m(default-jar)[m @ [36mdemo[0;1m ---[m [INFO] Building jar: E:\Dev\demo\target\demo-0.0.1-SNAPSHOT.jar [INFO] [INFO] [1m--- [0;32mspring-boot:3.3.3:repackage[m [1m(repackage)[m @ [36mdemo[0;1m ---[m [INFO] Replacing main artifact E:\Dev\demo\target\demo-0.0.1-SNAPSHOT.jar with repackaged archive, adding nested dependencies in BOOT-INF/. [INFO] The original artifact has been renamed to E:\Dev\demo\target\demo-0.0.1-SNAPSHOT.jar.original [INFO] [INFO] [1m--- [0;32minstall:3.1.3:install[m [1m(default-install)[m @ [36mdemo[0;1m ---[m [INFO] Installing E:\Dev\demo\pom.xml to C:\Users\Tutorialspoint\.m2\repository\com\tutorialspoint\demo\0.0.1-SNAPSHOT\demo-0.0.1-SNAPSHOT.pom [INFO] Installing E:\Dev\demo\target\demo-0.0.1-SNAPSHOT.jar to C:\Users\Tutorialspoint\.m2\repository\com\tutorialspoint\demo\0.0.1-SNAPSHOT\demo-0.0.1-SNAPSHOT.jar [INFO] [1m------------------------------------------------------------------------[m [INFO] [1;32mBUILD SUCCESS[m [INFO] [1m------------------------------------------------------------------------[m [INFO] Total time: 13.467 s [INFO] Finished at: 2024-09-25T15:57:08+05:30 [INFO] [1m------------------------------------------------------------------------[m
對於 Gradle,您可以使用以下命令:
gradle clean build