原文: http://zetcode.com/spring/mockmvc/

Spring MockMvc 教程展示了如何使用 MockMvc 测试 Spring MVC 应用。

Spring 是用于创建企业应用的流行 Java 应用框架。

MockMvc

MockMvc被定义为服务器端 Spring MVC 测试的主要入口点。 MockMvc的测试介于单元测试和集成测试之间。

Spring MockMvc 示例

以下应用使用MockMvc测试 Spring MVC 应用。 我们为模板和 RESTful 控制器方法创建测试。

  1. pom.xml
  2. src
  3. ├───main
  4. ├───java
  5. └───com
  6. └───zetcode
  7. ├───config
  8. MyWebInitializer.java
  9. WebConfig.java
  10. └───controller
  11. MyController.java
  12. ├───resources
  13. └───webapp
  14. └───WEB-INF
  15. └───templates
  16. index.html
  17. └───test
  18. └───java
  19. └───com
  20. └───zetcode
  21. └───controller
  22. MyControllerTest.java

这是项目结构。

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  5. http://maven.apache.org/xsd/maven-4.0.0.xsd">
  6. <modelVersion>4.0.0</modelVersion>
  7. <groupId>com.zetcode</groupId>
  8. <artifactId>mockmvcex</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. <packaging>war</packaging>
  11. <properties>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. <maven.compiler.source>11</maven.compiler.source>
  14. <maven.compiler.target>11</maven.compiler.target>
  15. <spring-version>5.1.3.RELEASE</spring-version>
  16. </properties>
  17. <dependencies>
  18. <dependency>
  19. <groupId>ch.qos.logback</groupId>
  20. <artifactId>logback-classic</artifactId>
  21. <version>1.2.3</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>javax.servlet</groupId>
  25. <artifactId>javax.servlet-api</artifactId>
  26. <version>4.0.1</version>
  27. <scope>provided</scope>
  28. </dependency>
  29. <dependency>
  30. <groupId>junit</groupId>
  31. <artifactId>junit</artifactId>
  32. <version>4.12</version>
  33. <scope>test</scope>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework</groupId>
  37. <artifactId>spring-webmvc</artifactId>
  38. <version>${spring-version}</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.springframework</groupId>
  42. <artifactId>spring-test</artifactId>
  43. <version>${spring-version}</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>org.thymeleaf</groupId>
  47. <artifactId>thymeleaf-spring5</artifactId>
  48. <version>3.0.11.RELEASE</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>org.thymeleaf</groupId>
  52. <artifactId>thymeleaf</artifactId>
  53. <version>3.0.11.RELEASE</version>
  54. </dependency>
  55. </dependencies>
  56. <build>
  57. <plugins>
  58. <plugin>
  59. <groupId>org.apache.maven.plugins</groupId>
  60. <artifactId>maven-war-plugin</artifactId>
  61. <version>3.2.2</version>
  62. </plugin>
  63. </plugins>
  64. </build>
  65. </project>

pom.xml文件中,我们具有以下依存关系:logback-classicjavax.servlet-apijunitspring-webmvcspring-testthymeleaf-spring5thymeleaf

com/zetcode/config/MyWebInitializer.java

  1. package com.zetcode.config;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
  4. @Configuration
  5. public class MyWebInitializer extends
  6. AbstractAnnotationConfigDispatcherServletInitializer {
  7. @Override
  8. protected Class<?>[] getRootConfigClasses() {
  9. return null;
  10. }
  11. @Override
  12. protected Class<?>[] getServletConfigClasses() {
  13. return new Class[]{WebConfig.class};
  14. }
  15. @Override
  16. protected String[] getServletMappings() {
  17. return new String[]{"/"};
  18. }
  19. }

MyWebInitializer注册 Spring DispatcherServlet,它是 Spring Web 应用的前端控制器。

  1. @Override
  2. protected Class<?>[] getServletConfigClasses() {
  3. return new Class[]{WebConfig.class};
  4. }

getServletConfigClasses()返回 Web 配置类。

com/zetcode/config/WebConfig.java

  1. package com.zetcode.config;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.ComponentScan;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.web.servlet.ViewResolver;
  8. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  9. import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
  10. import org.thymeleaf.spring5.SpringTemplateEngine;
  11. import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
  12. import org.thymeleaf.spring5.view.ThymeleafViewResolver;
  13. @Configuration
  14. @EnableWebMvc
  15. @ComponentScan(basePackages = {"com.zetcode"})
  16. public class WebConfig {
  17. @Autowired
  18. private ApplicationContext applicationContext;
  19. @Bean
  20. public SpringResourceTemplateResolver templateResolver() {
  21. var templateResolver = new SpringResourceTemplateResolver();
  22. templateResolver.setApplicationContext(applicationContext);
  23. templateResolver.setPrefix("/WEB-INF/templates/");
  24. templateResolver.setSuffix(".html");
  25. return templateResolver;
  26. }
  27. @Bean
  28. public SpringTemplateEngine templateEngine() {
  29. var templateEngine = new SpringTemplateEngine();
  30. templateEngine.setTemplateResolver(templateResolver());
  31. templateEngine.setEnableSpringELCompiler(true);
  32. return templateEngine;
  33. }
  34. @Bean
  35. public ViewResolver viewResolver() {
  36. var resolver = new ThymeleafViewResolver();
  37. var registry = new ViewResolverRegistry(null, applicationContext);
  38. resolver.setTemplateEngine(templateEngine());
  39. registry.viewResolver(resolver);
  40. return resolver;
  41. }
  42. }

WebConfig通过@EnableWebMvc启用 Spring MVC 注解,并为com.zetcode包配置组件扫描。 它设置了 Thymeleaf 引擎。

com/zetcode/controller/MyController.java

  1. package com.zetcode.controller;
  2. import org.springframework.http.MediaType;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.ui.Model;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.ResponseBody;
  7. import java.time.LocalDateTime;
  8. @Controller
  9. public class MyController {
  10. @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
  11. public String home(Model model) {
  12. model.addAttribute("now", LocalDateTime.now());
  13. return "index";
  14. }
  15. @GetMapping(value = "/message", produces = MediaType.TEXT_PLAIN_VALUE)
  16. @ResponseBody
  17. public String message() {
  18. return "Hello there!";
  19. }
  20. }

MyController提供了两种处理器方法。 home()方法返回具有单个属性的视图,message()方法返回纯文本消息。 在我们的测试中,我们测试这两种方法。

WEB-INF/templates/index.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Home page</title>
  6. </head>
  7. <body>
  8. <p>
  9. Today is: <span th:text="${now}"></span>
  10. </p>
  11. </body>
  12. </html>

这是index.html视图。

com/zetcode/controller/MyControllerTest.java

  1. package com.zetcode.controller;
  2. import org.junit.Before;
  3. import org.junit.Test;
  4. import org.springframework.test.web.servlet.MockMvc;
  5. import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
  6. import org.springframework.test.web.servlet.setup.MockMvcBuilders;
  7. import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
  8. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
  9. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  10. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
  11. public class MyControllerTest {
  12. private MockMvc mockMvc;
  13. @Before
  14. public void setup() {
  15. this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
  16. }
  17. @Test
  18. public void testHomePage() throws Exception {
  19. this.mockMvc.perform(get("/"))
  20. .andExpect(status().isOk())
  21. .andExpect(view().name("index"))
  22. .andDo(MockMvcResultHandlers.print())
  23. .andReturn();
  24. }
  25. @Test
  26. public void testMessagePage() throws Exception {
  27. this.mockMvc.perform(get("/message")).andExpect(status().isOk())
  28. .andExpect(content().string("Hello there!"));
  29. }
  30. }

MyControllerTest测试两个处理器。

  1. private MockMvc mockMvc;
  2. @Before
  3. public void setup() {
  4. this.mockMvc = MockMvcBuilders.standaloneSetup(new MyController()).build();
  5. }

我们设置了MockMvc。 我们将MyController添加到独立设置中。 MockMvcBuilders.standaloneSetup()允许注册一个或多个控制器,而无需使用完整的WebApplicationContext

  1. @Test
  2. public void testHomePage() throws Exception {
  3. this.mockMvc.perform(get("/"))
  4. .andExpect(status().isOk())
  5. .andExpect(view().name("index"))
  6. .andDo(MockMvcResultHandlers.print());
  7. }

我们测试主页。 我们验证状态和返回的视图名称。 我们还将打印结果。

  1. @Test
  2. public void testMessagePage() throws Exception {
  3. this.mockMvc.perform(get("/message")).andExpect(status().isOk())
  4. .andExpect(content().string("Hello there!"));
  5. }

我们测试消息页面。 由于它是一种 RESTful 方法,因此我们将验证状态和返回的字符串。

  1. $ mvn -q test

我们使用mvn -q test运行测试。

在本教程中,我们使用MockMvc为 Spring MVC 创建了测试。

您可能也对这些相关教程感兴趣: SpringRunner教程Java 教程