- 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