1. 概要
软件测试是一个应用软件质量的保证。java开发者开发接口往往忽视接口单元测试。作为java开发如果会Mock单元测试,那么你的bug量将会大大降低。spring提供test测试模块,所以现在小胖哥带你来玩下springboot下的Mock单元测试,我们将对controller,service 的单元测试进行实战操作。
2. 依赖引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
复制代码
按照上面引入依赖而且scope为 test 。该依赖提供了一下类库
- JUnit 4 : 目前最强大的java应用单元测试框架
- Spring Test & Spring Boot Test : Spring Boot 集成测试支持.
- AssertJ : 一个java断言库,提供测试断言支持.
- Hamcrest : 对象匹配断言和约束组件.
- Mockito : 知名 Java mock 模拟框架.
- JSONassert : JSON断言库.
- JsonPath : JSON XPath 操作类库.
以上都是在单元测试中经常接触的类库。有时间你最好研究一下。
3. 配置测试环境
一个Spring Boot 应用程序是一个
Spring ApplicationContext
,一般测试不会超出这个范围。
测试框架提供一个
@SpringBootTest
注解来提供SpringBoot单元测试环境支持。你使用的JUnit版本如果是
JUnit 4
不要忘记在测试类上添加
@RunWith(SpringRunner.class)
,
JUnit 5
就不需要了。默认情况下,@SpringBootTest不会启动服务器。您可以使用其
webEnvironment
属性进一步优化测试的运行方式,
webEnvironment
相关讲解:
-
MOCK
(默认):加载Web ApplicationContext并提供模拟Web环境。该选择下不会启动嵌入式服务器。如果类路径上没有Web环境,将创建常规非Web的ApplicationContext
。你可以配合@AutoConfigureMockMvc
或@AutoConfigureWebTestClient
模拟的Web应用程序。 -
RANDOM_PORT
:加载WebServerApplicationContext
并提供真实的Web环境,启用的是随机web容器端口。 -
DEFINED_PORT
:加载WebServerApplicationContext
并提供真实的Web环境 和RANDOM_PORT
不同的是启用你激活的SpringBoot应用端口,通常都声明在application.yml
配置文件中。 -
NONE
:通过SpringApplication
加载一个ApplicationContext
。但不提供 任何 Web环境(无论是Mock或其他)。
注意事项:如果你的测试带有
@Transactional
注解时,默认情况下每个测试方法执行完就会回滚事务。但是当你的
webEnvironment
设置为
RANDOM_PORT
或者
DEFINED_PORT
,也就是隐式地提供了一个真实的servlet web环境时,是不会回滚的。这一点特别重要,请确保不会在生产发布测试中写入脏数据。
4. 编写测试类测试你的api
言归正传,首先我们编写了一个
BookService
作为Service 层
package cn.felord.mockspringboot.service;
import cn.felord.mockspringboot.entity.Book;
/**
* The interface Book service.
*
* @author Dax
* @since 14 :54 2019-07-23
*/
public interface BookService {
/**
* Query by title book.
*
* @param title the title
* @return the book
*/
Book queryByTitle(String title);
}
复制代码
其实现类如下,为了简单明了没有测试持久层,如果持久层需要测试注意增删改需要Spring事务注解
@Transactional
支持以达到测试后回滚的目的。
package cn.felord.mockspringboot.service.impl;
import cn.felord.mockspringboot.entity.Book;
import cn.felord.mockspringboot.service.BookService;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
/**
* @author Dax
* @since 14:55 2019-07-23
*/
@Service
public class BookServiceImpl implements BookService {
@Override
public Book queryByTitle(String title) {
Book book = new Book();
book.setAuthor("dax");
book.setPrice(78.56);
book.setReleaseTime(LocalDate.of(2018, 3, 22));
book.setTitle(title);
return book;
}
}
复制代码
controller层如下:
package cn.felord.mockspringboot.api;
import cn.felord.mockspringboot.entity.Book;
import cn.felord.mockspringboot.service.BookService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author Dax
* @since