zoukankan      html  css  js  c++  java
  • SpringBoot使用Junit4单元测试

    SpringBoot2.0笔记

    本篇介绍Springboot单元测试的一些基本操作,有人说一个合格的程序员必须熟练使用单元测试,接下来我们一起在Springboot项目中整合Junit4单元测试。

    本文使用idea工具构建Springboot2.0+SpringMvc+Thymeleaf+SpringDataJPA+MySql项目

    GitHub地址:https://github.com/jwam/springbootJunit4.git

    一、IDEA下载并安装Junit插件

    点击file-settings,如图按照顺序操作即可,我这里已经安装过了所以最后一步不会显示install按钮。

     二、引入关键依赖,完整pom文末给出

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-test</artifactId>
    4. <scope>test</scope>
    5. </dependency>
    6. <dependency>
    7. <groupId>junit</groupId>
    8. <artifactId>junit</artifactId>
    9. <version>4.12</version>
    10. <!--<scope>test</scope>-->
    11. </dependency>
    12. <dependency>
    13. <groupId>org.springframework</groupId>
    14. <artifactId>spring-test</artifactId>
    15. <version>5.0.4.RELEASE</version>
    16. </dependency>
    17. <dependency>
    18. <groupId>org.springframework.boot</groupId>
    19. <artifactId>spring-boot-test</artifactId>
    20. <version>2.0.0.RELEASE</version>
    21. </dependency>

    三、新建UserController.java作为被测试类

    1. package com.springboot.demo.controller;
    2. import com.springboot.demo.base.controller.BaseController;
    3. import com.springboot.demo.base.utils.StateParameter;
    4. import com.springboot.demo.entity.User;
    5. import com.springboot.demo.service.UserService;
    6. import org.springframework.beans.factory.annotation.Autowired;
    7. import org.springframework.stereotype.Controller;
    8. import org.springframework.ui.ModelMap;
    9. import org.springframework.util.StringUtils;
    10. import org.springframework.web.bind.annotation.RequestMapping;
    11. import org.springframework.web.bind.annotation.RequestMethod;
    12. import org.springframework.web.bind.annotation.ResponseBody;
    13. import javax.servlet.http.HttpServletRequest;
    14. import java.util.Date;
    15. import java.util.List;
    16. /**
    17. * @ClassName: UserController
    18. * @Auther: zhangyingqi
    19. * @Date: 2018/8/27 17:30
    20. * @Description:
    21. */
    22. @Controller
    23. @RequestMapping(value="/user")
    24. public class UserController extends BaseController{
    25. @Autowired
    26. UserService userService;
    27. /**
    28. * @auther: zhangyingqi
    29. * @date: 17:37 2018/8/27
    30. * @param: [request, user]
    31. * @return: org.springframework.ui.ModelMap
    32. * @Description: 用户保存&更新
    33. */
    34. @RequestMapping(value="/add", method = RequestMethod.POST)
    35. @ResponseBody
    36. public ModelMap add(User user){
    37. try {
    38. if(StringUtils.isEmpty(user.getId())){
    39. user.setId(getUuid());
    40. }else{
    41. user.setUpdateDate(new Date());
    42. }
    43. userService.save(user);
    44. logger.info("保存成功");
    45. return getModelMap(StateParameter.SUCCESS, user, "保存成功");
    46. } catch (Exception e) {
    47. e.printStackTrace();
    48. return getModelMap(StateParameter.FAULT, null, "保存失败");
    49. }
    50. }
    51. /**
    52. * @auther: zhangyingqi
    53. * @date: 17:47 2018/8/27
    54. * @param: [id]
    55. * @return: org.springframework.ui.ModelMap
    56. * @Description: 删除用户
    57. */
    58. @RequestMapping(value="/delete", method = RequestMethod.GET)
    59. @ResponseBody
    60. public ModelMap delete(String id){
    61. try {
    62. User user = userService.findById(id);
    63. if(user==null){
    64. return getModelMap(StateParameter.FAULT, user, "找不到该用户");
    65. }
    66. userService.delete(user);
    67. logger.info("删除成功");
    68. return getModelMap(StateParameter.SUCCESS, null, "删除成功");
    69. } catch (Exception e) {
    70. e.printStackTrace();
    71. return getModelMap(StateParameter.FAULT, null, "删除失败");
    72. }
    73. }
    74. /**
    75. * @auther: zhangyingqi
    76. * @date: 17:47 2018/8/27
    77. * @param: [request]
    78. * @return: java.lang.String
    79. * @Description: 查询用户列表
    80. */
    81. @RequestMapping(value="/list")
    82. public String view(HttpServletRequest request){
    83. List<User> list = userService.findAll();
    84. request.setAttribute("list", list);
    85. logger.info("返回列表页面");
    86. return "/demoPage/listPage";
    87. }
    88. }

    UserController类中用到的其他依赖都可以去我文章开始提供的GitHub地址下载,其实看过我之前文章的人应该都知道,最简单的办法就是直接下载demo了,当然你也可以自己编写一个controller类,在本篇中并没有特别要求。

    当然不能少了实体类User.java,父类前几篇文章我都有写过,demo里也有,节省文本这里不再给出。

    1. package com.springboot.demo.entity;
    2. import lombok.Data;
    3. import javax.persistence.Column;
    4. import javax.persistence.Entity;
    5. import javax.persistence.Table;
    6. /**
    7. * @ClassName: User
    8. * @Auther: zhangyingqi
    9. * @Date: 2018/8/27 17:17
    10. * @Description:
    11. */
    12. @Entity
    13. @Table(name = "user")
    14. @Data
    15. public class User extends BaseEntity{
    16. @Column(name = "name", length = 100)
    17. private String name;
    18. @Column(name = "age")
    19. private int age;
    20. }

    另外还需要list方法返回的实际页面,在项目template下demoPage下新建listPage.html

    1. <!DOCTYPE html>
    2. <html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>用户列表</title>
    6. </head>
    7. <body>
    8. <div>
    9. <table>
    10. <thead>
    11. <tr>
    12. <th>用户名称</th>
    13. <th>年龄</th>
    14. <th>创建时间</th>
    15. </tr>
    16. </thead>
    17. <tbody>
    18. <tr th:if="${list !=null}" th:each="item : ${list}">
    19. <td th:text="${item.name}"></td>
    20. <td th:text="${item.age}"></td>
    21. <td th:text="${#dates.format(item.create_date, 'yyyy-MM-dd')}"></td>
    22. </tr>
    23. </tbody>
    24. </table>
    25. </div>
    26. </body>
    27. </html>

    四、生成单元测试类

    在UserController中按住alt+insert键,如图选择将自动生成测试类。

     这时Junit工具将自动生成一个test目录,在同路径下生成同类名+Test组合名称UserControllerTest.java类,这就是自动生成的测试类。

     我们改造这个测试类的内容

    首先在类名上加入注解@RunWith和@SpringBootTest,后者需指定springboot启动类

    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest(classes = DemoApplication.class)
    3. public class UserControllerTest {
    4. }

    然后引入MockMvc对象及WebApplicationContext上下文,如果涉及业务的测试内容还需引入其他依赖,@Before表示在测试方法执行之前执行会该方法,所以我们在这里实例化mockmvc对象,这样后面就可以操作他了。

    1. @RunWith(SpringRunner.class)
    2. @SpringBootTest(classes = DemoApplication.class)
    3. public class UserControllerTest {
    4. /**
    5. * 模拟mvc测试对象
    6. */
    7. private MockMvc mockMvc;
    8. /**
    9. * web项目上下文
    10. */
    11. @Autowired
    12. private WebApplicationContext webApplicationContext;
    13. /**
    14. * 业务数据接口
    15. */
    16. @Autowired
    17. private UserService userService;
    18. /**
    19. * 所有测试方法执行之前执行该方法
    20. */
    21. @Before
    22. public void before() {
    23. //获取mockmvc对象实例
    24. mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    25. }
    26. }

    接下来我们编写测试代码,首先对UserController中的查询用户列表方法进行测试,方法头部需添加@Test注解,具体方法内容如下,使用MockMvcRequestBuilders模拟get请求,status接收返回状态,responseString接收返回的内容。Assert.assertEquals

    为通用的判断测试执行结果方法,其中三个参数分别为:不一致时提示信息,预期得到结果,实际得到结果。

    1. @Test
    2. public void testPage() throws Exception {
    3. MvcResult mvcResult = mockMvc
    4. .perform(// 1
    5. MockMvcRequestBuilders.get("/user/list") // 2
    6. //.param("name","getList") // 3
    7. )
    8. .andReturn();// 4
    9. int status = mvcResult.getResponse().getStatus(); // 5
    10. String responseString = mvcResult.getResponse().getContentAsString(); // 6
    11. Assert.assertEquals("请求错误", 200, status); // 7
    12. Assert.assertEquals("返回结果不一致", "/demoPage/listPage", responseString); // 8
    13. }

     接下来执行这个单元测试模块,IDEA自动检测到这是一个测试方法,我们直接点击方法左边的启动按钮即可,因为我已经执行过并且测试未通过,所以显示红色,本来是绿色。

     如果执行成功会提示success,我这里提供的这个测试方法执行后是报失败的,具体原因是在列表页面获取不到实体中的create_date字段

    做如下修改,将create_date改为createDate即可,所以我们可以看到,测试页面时会去渲染方法返回的整个html页面,如果有语法错误将会报错,测试执行失败。

    1. <tbody>
    2. <tr th:if="${list !=null}" th:each="item : ${list}">
    3. <td th:text="${item.name}"></td>
    4. <td th:text="${item.age}"></td>
    5. <td th:text="${#dates.format(item.create_date, 'yyyy-MM-dd')}"></td>
    6. </tr>
    7. </tbody>

    再次启动测试单元测试不再报错,但是依旧执行失败,提示“返回结果不一致”,我们点击结果对比发现返回结果有差异,所以未达到期望,直接返回了不一致时的提示信息,因此我们在测试返回页面时只需执行Assert.assertEquals("请求错误", 200, status); 即可,不必再判断返回期望。

     注释掉返回结果预期判断之后执行测试成功。

     那么返回结果预期判断怎么用呢,我们看下面的第二个测试删除用户方法,param可以添加传递的参数,预期结果为删除成功,我这里模拟了删除成功后的返回json数据,实际应用中可根据情况设定。

     可以看到后台打印删除成功,同时单元测试执行通过。

    本篇我通过Junit4单元测试对springboot项目的controller类进行测试,掌握基本的单元测试在springboot中整合的使用方法。

    下面给出完整的pom包,推荐大家直接下载文首给出的demo,可以直接运行,方便又快捷。

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4. <modelVersion>4.0.0</modelVersion>
    5. <groupId>com.springboot</groupId>
    6. <artifactId>springbootJunit4</artifactId>
    7. <version>0.0.1-SNAPSHOT</version>
    8. <packaging>war</packaging>
    9. <name>springbootJunit4</name>
    10. <description>Demo project for Spring Boot</description>
    11. <parent>
    12. <groupId>org.springframework.boot</groupId>
    13. <artifactId>spring-boot-starter-parent</artifactId>
    14. <version>2.0.4.RELEASE</version>
    15. <relativePath/> <!-- lookup parent from repository -->
    16. </parent>
    17. <properties>
    18. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    19. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    20. <java.version>1.8</java.version>
    21. </properties>
    22. <dependencies>
    23. <dependency>
    24. <groupId>org.springframework.boot</groupId>
    25. <artifactId>spring-boot-starter-tomcat</artifactId>
    26. <!--<scope>provided</scope>-->
    27. </dependency>
    28. <dependency>
    29. <groupId>org.springframework.boot</groupId>
    30. <artifactId>spring-boot-starter-data-jpa</artifactId>
    31. <exclusions>
    32. <exclusion>
    33. <groupId>org.hibernate</groupId>
    34. <artifactId>hibernate-entitymanager</artifactId>
    35. </exclusion>
    36. <exclusion>
    37. <groupId>org.hibernate</groupId>
    38. <artifactId>hibernate-core</artifactId>
    39. </exclusion>
    40. </exclusions>
    41. </dependency>
    42. <dependency>
    43. <groupId>org.hibernate</groupId>
    44. <artifactId>hibernate-core</artifactId>
    45. <version>5.2.10.Final</version>
    46. </dependency>
    47. <dependency>
    48. <groupId>org.springframework.boot</groupId>
    49. <artifactId>spring-boot-starter-data-redis</artifactId>
    50. </dependency>
    51. <dependency>
    52. <groupId>org.springframework.boot</groupId>
    53. <artifactId>spring-boot-starter-mail</artifactId>
    54. </dependency>
    55. <dependency>
    56. <groupId>org.springframework.boot</groupId>
    57. <artifactId>spring-boot-starter-thymeleaf</artifactId>
    58. </dependency>
    59. <dependency>
    60. <groupId>org.springframework.boot</groupId>
    61. <artifactId>spring-boot-starter-web</artifactId>
    62. </dependency>
    63. <dependency>
    64. <groupId>mysql</groupId>
    65. <artifactId>mysql-connector-java</artifactId>
    66. <scope>runtime</scope>
    67. </dependency>
    68. <dependency>
    69. <groupId>org.projectlombok</groupId>
    70. <artifactId>lombok</artifactId>
    71. <optional>true</optional>
    72. </dependency>
    73. <dependency>
    74. <groupId>org.springframework.boot</groupId>
    75. <artifactId>spring-boot-starter-test</artifactId>
    76. <scope>test</scope>
    77. </dependency>
    78. <dependency>
    79. <groupId>junit</groupId>
    80. <artifactId>junit</artifactId>
    81. <version>4.12</version>
    82. <!--<scope>test</scope>-->
    83. </dependency>
    84. <dependency>
    85. <groupId>org.springframework</groupId>
    86. <artifactId>spring-test</artifactId>
    87. <version>5.0.4.RELEASE</version>
    88. </dependency>
    89. <dependency>
    90. <groupId>org.springframework.boot</groupId>
    91. <artifactId>spring-boot-test</artifactId>
    92. <version>2.0.0.RELEASE</version>
    93. </dependency>
    94. </dependencies>
    95. <build>
    96. <plugins>
    97. <plugin>
    98. <groupId>org.springframework.boot</groupId>
    99. <artifactId>spring-boot-maven-plugin</artifactId>
    100. </plugin>
    101. </plugins>
    102. </build>
    103. </project>

    全文完,2018/8/30

    原文地址:https://blog.csdn.net/zhulier1124/article/details/82228831

  • 相关阅读:
    SpringMVC基础知识
    git pull 和git fetch的区别
    动态规划的原理?
    为什么要使用volatile修饰呢?
    内部类,匿名内部类?
    什么是性能优化?
    如何定位CPU瓶颈?
    什么是程序的耦合?
    什么是性能优化?
    Class类的常用方法?
  • 原文地址:https://www.cnblogs.com/jpfss/p/10950514.html
Copyright © 2011-2022 走看看