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
这是项目结构。
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
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>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring-version>5.1.3.RELEASE</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</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.2.2</version>
</plugin>
</plugins>
</build>
</project>
在pom.xml
文件中,我们具有以下依存关系:logback-classic
,javax.servlet-api
,junit
,spring-webmvc
,spring-test
,thymeleaf-spring5
和thymeleaf
。
com/zetcode/config/MyWebInitializer.java
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 配置类。
com/zetcode/config/WebConfig.java
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 引擎。
com/zetcode/controller/MyController.java
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()
方法返回纯文本消息。 在我们的测试中,我们测试这两种方法。
WEB-INF/templates/index.html
<!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
视图。
com/zetcode/controller/MyControllerTest.java
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 创建了测试。