Spring Boot中的测试
Spring Boot中的测试
简介
本篇文章我们将会探讨一下怎么在SpringBoot使用测试,Spring Boot有专门的spring-boot-starter-test,通过使用它可以很方便的在Spring Boot进行测试。
本文将从repository,service, controller,app四个层级来详细描述测试案例。
添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
我们添加spring-boot-starter-test和com.h2database总共两个依赖。H2数据库主要是为了测试方便。
Repository测试
本例中,我们使用JPA,首先创建Entity和Repository:
@Entity
@Table(name = "person")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Size(min = 3, max = 20)
private String name;
// standard getters and setters, constructors
}
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
public Employee findByName(String name);
}
测试JPA,我们需要使用@DataJpaTest:
@RunWith(SpringRunner.class)
@DataJpaTest
public class EmployeeRepositoryIntegrationTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private EmployeeRepository employeeRepository;
// write test cases here
}
@RunWith(SpringRunner.class) 是Junit和Spring Boot test联系的桥梁。
@DataJpaTest为persistence layer的测试提供了如下标准配置:
- 配置H2作为内存数据库
- 配置Hibernate, Spring Data, 和 DataSource
- 实现@EntityScan
- 开启SQL logging
下面是我们的测试代码:
@Test
public void whenFindByName_thenReturnEmployee() {
// given
Employee alex = new Employee("alex");
entityManager.persist(alex);
entityManager.flush();
// when
Employee found = employeeRepository.findByName(alex.getName());
// then
assertThat(found.getName())
.isEqualTo(alex.getName());
}
在测试中,我们使用了TestEntityManager。 TestEntityManager提供了一些通用的对Entity操作的方法。上面的例子中我们使用TestEntityManager向Employee插入了一条数据。
Service测试
在实际的应用程序中,Service通常要使用到Repository。但是在测试中我们可以Mock一个Repository,而不用使用真实的Repository。
先看一下Service:
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public Employee getEmployeeByName(String name) {
return employeeRepository.findByName(name);
}
}
我们再看一下怎么Mock Repository。
@RunWith(SpringRunner.class)
public class EmployeeServiceImplIntegrationTest {
@TestConfiguration
static class EmployeeServiceImplTestContextConfiguration {
@Bean
public EmployeeService employeeService() {
return new EmployeeServiceImpl();
}
}
@Autowired
private EmployeeService employeeService;
@MockBean
private EmployeeRepository employeeRepository;
// write test cases here
}
看下上面的例子,我们首先使用了@TestConfiguration专门用在测试中的配置信息,在@TestConfiguration中,我们实例化了一个EmployeeService Bean,然后在EmployeeServiceImplIntegrationTest自动注入。
我们还是用了@MockBean,用来Mock一个EmployeeRepository。
我们看下Mock的实现:
@Before
public void setUp() {
Employee alex = new Employee("alex");
Mockito.when(employeeRepository.findByName(alex.getName()))
.thenReturn(alex);
}
@Test
public void whenValidName_thenEmployeeShouldBeFound() {
String name = "alex";
Employee found = employeeService.getEmployeeByName(name);
assertThat(found.getName())
.isEqualTo(name);
}
上面的代码中,我们使用Mockito来Mock要返回的数据,然后在接下来的测试中使用。
测试Controller
和测试Service一样,Controller使用到了Service:
@RestController
@RequestMapping("/api")
public class EmployeeRestController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/employees")
public List<Employee> getAllEmployees() {
return employeeService.getAllEmployees();
}
}
但是在测试的时候,我们并不需要使用真实的Service,我们需要Mock它 。
@RunWith(SpringRunner.class)
@WebMvcTest(EmployeeRestController.class)
public class EmployeeControllerIntegrationTest {
@Autowired
private MockMvc mvc;
@MockBean
private EmployeeService service;
// write test cases here
为了测试Controller,我们需要使用到@WebMvcTest,他会为Spring MVC 自动配置所需的组件。
通常情况下@WebMvcTest 会和@MockBean一起使用来提供Mock的具体实现。
@WebMvcTest也提供了自动配置的MockMvc,它为测试MVC Controller提供了更加简单的方式,而不需要启动完整的HTTP server。
@Test
public void givenEmployees_whenGetEmployees_thenReturnJsonArray()
throws Exception {
Employee alex = new Employee("alex");
List<Employee> allEmployees = Arrays.asList(alex);
given(service.getAllEmployees()).willReturn(allEmployees);
mvc.perform(get("/api/employees")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$", hasSize(1)))
.andExpect(jsonPath("$[0].name", is(alex.getName())));
}
given(service.getAllEmployees()).willReturn(allEmployees); 这一行代码提供了mock的输出。方面后面的测试使用。
@SpringBootTest的集成测试
上面我们讲的都是单元测试,这一节我们讲一下集成测试。
@RunWith(SpringRunner.class)
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = TestApplication.class)
@AutoConfigureMockMvc
@TestPropertySource(
locations = "classpath:application-integrationtest.properties")
public class EmployeeAppIntegrationTest {
@Autowired
private MockMvc mvc;
@Autowired
private EmployeeRepository repository;
}
集成测试需要使用@SpringBootTest,在@SpringBootTest中可以配置webEnvironment,同时如果我们需要自定义测试属性文件可以使用@TestPropertySource。
下面是具体的测试代码:
@After
public void resetDb() {
repository.deleteAll();
}
@Test
public void givenEmployees_whenGetEmployees_thenStatus200() throws Exception {
createTestEmployee("bob");
createTestEmployee("alex");
// @formatter:off
mvc.perform(get("/api/employees").contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", hasSize(greaterThanOrEqualTo(2))))
.andExpect(jsonPath("$[0].name", is("bob")))
.andExpect(jsonPath("$[1].name", is("alex")));
// @formatter:on
}
//
private void createTestEmployee(String name) {
Employee emp = new Employee(name);
repository.saveAndFlush(emp);
}
本文的例子可以参考https://github.com/ddean2009/learn-springboot2/tree/master/springboot-test
更多教程请参考 flydean的博客
Spring Boot中的测试的更多相关文章
- Spring Boot 中的测试:JUnit
官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html
- spring boot(三):Spring Boot中Redis的使用
spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...
- Spring Boot中的事务管理
原文 http://blog.didispace.com/springboottransactional/ 什么是事务? 我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多步操作的结合 ...
- Spring Boot中使用Swagger2构建强大的RESTful API文档
由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这 ...
- springboot(十一):Spring boot中mongodb的使用
mongodb是最早热门非关系数据库的之一,使用也比较普遍,一般会用做离线数据分析来使用,放到内网的居多.由于很多公司使用了云服务,服务器默认都开放了外网地址,导致前一阵子大批 MongoDB 因配置 ...
- springboot(三):Spring boot中Redis的使用
spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...
- spring boot项目如何测试,如何部署
有很多网友会时不时的问我,spring boot项目如何测试,如何部署,在生产中有什么好的部署方案吗?这篇文章就来介绍一下spring boot 如何开发.调试.打包到最后的投产上线. 开发阶段 单元 ...
- 在Spring Boot中使用数据缓存
春节就要到了,在回家之前要赶快把今年欠下的技术债还清.so,今天继续.Spring Boot前面已经预热了n篇博客了,今天我们来继续看如何在Spring Boot中解决数据缓存问题.本篇博客是以初识在 ...
- 在Spring Boot中使用数据库事务
我们在前面已经分别介绍了如何在Spring Boot中使用JPA(初识在Spring Boot中使用JPA)以及如何在Spring Boot中输出REST资源(在Spring Boot中输出REST资 ...
随机推荐
- ScheduledThreadPoolExecutor之remove方法
之前用定时任务的线程池,设置了个任务,但是突然今天产品说,某些个操作需要中断某些任务(如果任务还没有执行),使其不能再到点执行了.于是查了API果然有这样一个方法. 一看API,需要移除的是一个Run ...
- 一分钟 Get 时序数据库 InfluxDB 的技能
1. 通过上期分享<实践指路明灯,源码剖析flink-metrics>,对当下较火的流式处理框架 flink 的指标监控体系有了全局的认识,并结合 flink-metrics-xxxx 模 ...
- ServletConfig&ServletContext对比
上下文初始化参数(ServletContext) Servlet初始化参数(ServletConfig) 部署描述文件 在<web-app>元素中,但是不在具体的<servlet&g ...
- Shell:Day10
shell脚本:明白一点:shell脚本本身是一个工具 在写shell脚本之前,就要明白:这个功能能到底如何实现? curl 访问文件源代码,查看网站状态: 才能通过shell(bash)所提供的逻辑 ...
- Redis系列(五):Redis的过期键删除策略
本篇博客是Redis系列的第5篇,主要讲解下Redis的过期键删除策略. 本系列的前4篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装 Redis系列(二):Redis的5种数 ...
- Spring (六):整合Mybatis
本文是按照狂神说的教学视频学习的笔记,强力推荐,教学深入浅出一遍就懂!b站搜索狂神说或点击下面链接 https://space.bilibili.com/95256449?spm_id_from=33 ...
- python基本知识点if、while、等等
给予Python的相关知识点: 主要是对于基本语句的相关使用if else while for等先关的应用,以及步骤如下: 尝试编程如下:还有就是对于 import math import rando ...
- Python 1基础语法一(注释、行与缩进、多行语句、空行和代码组)
一.注释Python中单行注释以 # 开头,实例如下: # 第一个注释 print ("Hello, Python!") # 第二个注释 输出结果为: ============== ...
- 萌新带你开车上p站(Ⅳ)
本文作者:萌新 前情回顾: 萌新带你开车上p站(一) 萌新带你开车上p站(二) 萌新带你开车上P站(三) 回顾一下前篇,我们开始新的内容吧 0x12 登录后看源码 通读程序,逻辑是这样子的: 输入6个 ...
- threejs创建地球
上个月底,在朋友圈看到一个号称“这可能是地球上最美的h5”的分享,点进入后发现这个h5还很别致,思考了一会,决定要不高仿一个? 到今天为止,高仿基本完成, 线上地址 github地址 除了手机端的me ...