首页 > 编程笔记 > Java笔记

Spring Boot单元测试详解

单元测试在日常项目开发中必不可少,Spring Boot 提供了完善的单元测试框架和工具用于测试开发的应用,本文将介绍 Spring Boot 为单元测试提供了哪些支持,以及如何在 Spring Boot 项目中进行单元测试。

Spring Boot集成单元测试

单元测试主要用于测试单个代码组件,以确保代码按预期方式工作。目前流行的有 JUnit 或 TestNG 等测试框架。Spring Boot 封装了单元测试组件 spring-boot-starter-test。

下面通过示例演示 Spring Boot 是如何实现单元测试的。

1) 引入依赖

首先创建 Spring Boot 项目。在项目中引入 spring-boot-starter-test 组件,示例配置如下:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

2) 创建单元测试

在 src/test 目录下新建一个 HelloTest 测试类,如果只想输出一句“Hello Spring Boot Test”,只需要用一个 @Test 注解即可。

示例代码如下:
@SpringBootTest
public class HelloTest {
    @Test
    public void hello(){
        System.out.println("Hello Spring Boot Test");
    }
}
在类的上面添加 @SpringBootTest 注解,系统会自动把这段程序加载到 Spring Boot 容器。@Test 注解表示该方法为单元测试方法。

3) 运行单元测试

单击 Run Test 或在方法上右击,再选择“Run 'hello'”,运行测试方法,运行结果如下图所示。


图 1 单元测试的运行结果

由图 1 可知,单元测试方法运行成功并输出相应的结果,同时 IDEA 也会显示运行的所有单元测试结果,包括测试是否通过、运行时间、测试总数和成功次数等。

以上示例中的测试方法只是 spring-boot-starter-test 组件中的一部分功能,Spring Boot 自带的 spring-boot-starter-test 框架对测试的支持非常完善,包括 Web 请求测试、Service 方法测试等,后面会逐一介绍。

测试Service方法

一般使用 Spring Boot 进行单元测试主要是针对 Service 和 API(Controller)进行。接下来通过示例演示 Spring Boot 如何测试 Service 方法。

1) 创建Service测试类

创建 Service 测试类非常简单,使用 IDEA 可以一键自动创建单元测试类。首先,选择需要测试的 Service 类或方法,然后在对应的 Service 类中右击,选择Go To→Test→Create New Test,打开如下图所示的创建测试类界面。


图 2 IDEA创建测试类界面

单击 OK 按钮,IDEA 会在 Test 目录下创建一个 UserServiceTest 测试类,并为勾选的测试类自动生成单元测试的方法。

2) 实现单元测试

在上面创建好的 UserServiceTest 类中会自动创建对应的单元测试方法,我们只需要在测试方法中实现对应的测试代码即可,具体的示例代码如下:
@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService userService;

    @Test
    public void findOne() throws Exception {
        Assert.assertEquals("1002", userService.findOne());
    }
}
如以上示例代码所示,在自动测试类上增加 @SpringBootTest 注解即可。首先注入需要测试的 Service,然后在单元测试中调用该方法,最后通过 Assert 断句判断返回结果是否正确。

执行单元测试也非常简单,只需将鼠标放在对应的方法上,右击并选择 Run 执行该方法即可。

测试Controller接口方法

上面是针对 Service 进行测试,但是有时需要对 API(Controller)进行测试,这时需要用到 MockMvc 类。

MockMvc 能够模拟 HTTP 请求,使用网络的形式请求 Controller 中的方法,这样可以使得测试速度快、不依赖网络环境,而且它提供了一套完善的结果验证工具,测试和验证也非常简单、高效。

spring-boot-starter-test 具备强大的 Mock 能力,使用 @WebMvcTest 等注解实现模拟 HTTP 请求测试。下面通过示例演示如何测试 Controller 接口。

1) 创建 Controller 的测试类 HelloControllerTest,实现单元测试方法。示例代码如下:
@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    public void hello() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.post("/hello")   //执行一个请求
                .contentType(MediaType.APPLICATION_JSON))       //接收的数据类型
                .andExpect(status().isOk())  //添加执行完成后的断句,请求的状态响应码//是否为200,如果不是则测试不通过
                .andDo(print()); //添加一个结果处理程序,表示要对结果进行处理,比如此处//使用print()输出整个响应结果信息
    }
}
在上面的示例中,通过使用 MockMvc 构造一个 post 请求,MockMvcRequestBuilders 可以支持 post 和 get 请求,调用 print() 方法将请求和相应的过程都打印出来。

示例代码说明如下:
2) 完成测试方法之后,执行测试方法:将鼠标放在对应的方法上,右击并选择 Run 执行该方法即可。可以看到输出如下:
MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /hello
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8"]
             Body = null
    Session Attrs = {}

Handler:
             Type = com.weiz.helloworld.web.HelloController
           Method = com.weiz.helloworld.web.HelloController#hello()
Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"17"]
     Content type = text/plain;charset=UTF-8
             Body = hello Spring Boot
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
从上面的输出中可以看到,返回完整的 Http Response,包括 Status=200、Body = hello Spring Boot,说明接口请求成功并成功返回。

如果接口有登录验证,则需要通过 MockHttpSession 注入用户登录信息,或者修改登录拦截器取消对单元测试的登录验证。

常用的单元测试注解

在实际项目中,除了 @SpringBootTest、@Test 等注解之外,单元测试还有很多非常实用的注解,具体说明如下表所示。

表 3 单元测试类常用注解
注解 说明
@RunWith(SpringRunner.class) 声明测试运行在 Spring 环境。SpringRunner 是 SpringJUnit4ClassRunner 的新名字,这样做仅仅是为了让名字看起来更简单一点。
@SpringBootTest 用于 Spring Boot 应用测试,它默认会根据包名逐级往上找,一直找到 Spring Boot 主程序,通过类注解是否包含 @SpringBootApplication 来判断是否为主程序,并在测试时启动该类来创建 Spring 上下文环境。
@BeforeClass 针对所有测试,只执行一次,并且必须为 static void。
@BeforeEach 初始化方法,在当前测试类的每个测试方法前执行。
@Test 测试方法,在这里可以测试期望异常和超时时间。
@AfterEach 释放资源,在当前测试类的每个测试方法后执行。
@AfterClass 针对所有测试,只执行一次,且必须为 static void。
@Ignore 忽略的测试方法。

声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。