Spring MockMvc 教程
最后修改于 2023 年 10 月 18 日
Spring MockMvc 教程展示了如何使用 MockMvc 测试 Spring MVC 应用程序。
Spring 是一个流行的 Java 应用程序框架,用于创建企业级应用程序。
MockMvc
MockMvc 被定义为服务器端 Spring MVC 测试的主要入口点。使用 MockMvc 进行的测试介于单元测试和集成测试之间。
Spring MockMvc 示例
下面的应用程序使用 MockMvc 来测试 Spring MVC 应用程序。我们为模板和 RESTful 控制器方法创建了测试。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ ├───config
│ │ │ MyWebInitializer.java
│ │ │ WebConfig.java
│ │ └───controller
│ │ MyController.java
│ ├───resources
│ └───webapp
│ └───WEB-INF
│ └───templates
│ index.html
└───test
└───java
└───com
└───zetcode
└───controller
MyControllerTest.java
这是项目结构。
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>mockmvcex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<spring-version>5.3.23</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
</plugin>
</plugins>
</build>
</project>
在 pom.xml 文件中,我们有以下依赖项:logback-classic、javax.servlet-api、junit、spring-webmvc、spring-test、thymeleaf-spring5 和 thymeleaf。
package com.zetcode.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@Configuration
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
MyWebInitializer 注册了 Spring DispatcherServlet,它是 Spring Web 应用程序的前端控制器。
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
getServletConfigClasses 返回一个 Web 配置类。
package com.zetcode.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.zetcode"})
public class WebConfig {
@Autowired
private ApplicationContext applicationContext;
@Bean
public SpringResourceTemplateResolver templateResolver() {
var templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
var templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
@Bean
public ViewResolver viewResolver() {
var resolver = new ThymeleafViewResolver();
var registry = new ViewResolverRegistry(null, applicationContext);
resolver.setTemplateEngine(templateEngine());
registry.viewResolver(resolver);
return resolver;
}
}
WebConfig 使用 @EnableWebMvc 启用 Spring MVC 注释,并为 com.zetcode 包配置组件扫描。它设置了 Thymeleaf 引擎。
package com.zetcode.controller;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.time.LocalDateTime;
@Controller
public class MyController {
@GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
public String home(Model model) {
model.addAttribute("now", LocalDateTime.now());
return "index";
}
@GetMapping(value = "/message", produces = MediaType.TEXT_PLAIN_VALUE)
@ResponseBody
public String message() {
return "Hello there!";
}
}
MyController 提供了两个处理程序方法。home 方法返回一个带有单个属性的视图,而 message 方法返回一个纯文本消息。在我们的测试中,我们测试这两个方法。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Home page</title>
</head>
<body>
<p>
Today is: <span th:text="${now}"></span>
</p>
</body>
</html>
这是 index.html 视图。
package com.zetcode.controller;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
public class MyControllerTest {
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
}
@Test
public void testHomePage() throws Exception {
this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andDo(MockMvcResultHandlers.print())
.andReturn();
}
@Test
public void testMessagePage() throws Exception {
this.mockMvc.perform(get("/message")).andExpect(status().isOk())
.andExpect(content().string("Hello there!"));
}
}
MyControllerTest 测试这两个处理程序。
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
}
我们设置了 MockMvc。我们将 MyController 添加到独立设置中。MockMvcBuilders.standaloneSetup 允许注册一个或多个控制器,而无需使用完整的 WebApplicationContext。
@Test
public void testHomePage() throws Exception {
this.mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("index"))
.andDo(MockMvcResultHandlers.print());
}
我们测试了主页。我们验证了状态码和返回的视图名称。我们还打印了结果。
@Test
public void testMessagePage() throws Exception {
this.mockMvc.perform(get("/message")).andExpect(status().isOk())
.andExpect(content().string("Hello there!"));
}
我们测试了消息页面。由于这是一个 RESTful 方法,我们验证了状态码和返回的字符串。
$ mvn -q test
我们使用 mvn -q test 运行测试。
在本文中,我们使用 MockMvc 为 Spring MVC 创建了测试。
作者
列出 所有 Spring 教程。