文章目录
1. 加载测试专用属性
测试过程本身并不是一个复杂的过程,但是很多情况下测试时需要模拟一些线上情况,或者模拟一些特殊情况。但是在测试过程中,我们能不能每次测试的时候都去修改源码application.yml中的配置进行测试呢?显然是不行的。每次测试前改过来,每次测试后改回去,这太麻烦了。于是我们就想,需要在测试环境中创建一组临时属性,去覆盖我们源码中设定的属性,这样测试用例就相当于是一个独立的环境,能够独立测试,这样就方便多了。
- 临时属性
springboot已经为我们开发者早就想好了这种问题该如何解决,并且提供了对应的功能入口。在测试用例程序中,可以通过对注解@SpringBootTest添加属性来模拟临时属性,具体如下:
首先我们先看一下我们的application.yml文件
test:
prop: testValue
测试案例
//properties属性可以为当前测试用例添加临时的属性配置
@SpringBootTest(properties = {"test.prop=testValue1"})
public class PropertiesAndArgsTest {
@Value("${test.prop}")
private String msg;
@Test
void testProperties(){
System.out.println(msg);
}
}
通过临时属性的设置就能覆盖我们在yml中的属性设置了
- 临时参数
//args属性可以为当前测试用例添加临时的命令行参数
@SpringBootTest(args={"--test.prop=testValue2"})
public class PropertiesAndArgsTest {
@Value("${test.prop}")
private String msg;
@Test
void testProperties(){
System.out.println(msg);
}
}
肯定有小伙伴好奇说,那如果三种配置情况都存在的话springboot会选择哪一种呢,我们运行一下就知到了嘛。
总结
- 加载测试临时属性可以通过注解@SpringBootTest的properties和args属性进行设定,此设定应用范围仅适用于当前测试用例
2. 加载测试专用配置
学习过Spring的知识,我们都知道,其实一个spring环境中可以设置若干个配置文件或配置类,若干个配置信息可以同时生效。现在我们的需求就是在测试环境中再添加一个配置类,然后启动测试环境时,生效此配置就行了。其实做法和spring环境中加载多个配置信息的方式完全一样。具体操作步骤如下:
- 在测试包test中创建专用的测试环境配置类
@Configuration
public class MsgConfig {
@Bean
public String msg(){
return "this is bean msg";
}
}
- 在启动测试环境时,导入测试环境专用的配置类,使用@Import注解即可实现
@SpringBootTest
//在启动测试环境时,导入测试环境专用的配置类,使用@Import注解即可实现
@Import(MsgConfig.class)
public class BeanTest {
@Autowired
private String msg;
@Test
void testBean(){
System.out.println(msg);
}
}
总结
- 定义测试环境专用的配置类,然后通过@Import注解在具体的测试中导入临时的配置,例如测试用例,方便测试过程,且上述配置不影响其他的测试类环境
3. Web环境模拟测试
在测试中对表现层功能进行测试需要一个基础和一个功能。所谓的一个基础是运行测试程序时,必须启动web环境,不然没法测试web功能。一个功能是必须在测试程序中具备发送web请求的能力,不然无法实现web功能的测试。所以在测试用例中测试表现层接口这项工作就转换成了两件事,一,如何在测试类中启动web测试,二,如何在测试类中发送web请求。
3.1 启动web测试
每一个springboot的测试类上方都会标准@SpringBootTest注解,而注解带有一个属性,叫做webEnvironment。通过该属性就可以设置在测试用例中启动web环境,具体如下:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebTest {
}
测试类中启动web环境时,可以指定启动的Web环境对应的端口,这里我们设置一个随机端口
3.2 测试类中发送请求
对于测试类中发送请求,其实java的API就提供对应的功能,只不过平时各位小伙伴接触的比较少,所以较为陌生。springboot为了便于开发者进行对应的功能开发,对其又进行了包装,简化了开发步骤。
- 在测试类中开启web虚拟调用功能,通过注解@AutoConfigureMockMvc实现此功能的开启
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
@AutoConfigureMockMvc
public class WebTest {
}
- 定义发起虚拟调用的对象MockMVC,通过自动装配的形式初始化对象
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
@AutoConfigureMockMvc
public class WebTest {
@Test
void testWeb(@Autowired MockMvc mvc) {
}
}
- 创建一个虚拟请求对象,封装请求的路径,并使用MockMVC对象发送对应请求
@SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟MVC调用
@AutoConfigureMockMvc
public class WebTest {
@Test
//注入虚拟MVC调用对象
public void testWeb(@Autowired MockMvc mvc) throws Exception {
//创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
//执行请求
ResultActions action = mvc.perform(builder);
}
接下来我们运行测试观察controller是否被调用
可以看出,已经成功被调用了。
总结
- 在测试类中测试web层接口要保障测试类启动时启动web容器,使用@SpringBootTest注解的webEnvironment属性可以虚拟web环境用于测试
- 为测试方法注入MockMvc对象,通过MockMvc对象可以发送虚拟请求,模拟web请求调用过程
3.3 响应状态匹配
@Test
public void testStatus(@Autowired MockMvc mvc) throws Exception {
//创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
//MockHttpServletRequestBuilder builder1 = MockMvcRequestBuilders.get("/books1");
//执行请求
ResultActions action = mvc.perform(builder);
//匹配执行状态(是否预期值)
//定义执行状态匹配器
StatusResultMatchers status = MockMvcResultMatchers.status();
//定义预期执行状态
ResultMatcher ok = status.isOk();
//使用本次真实值与预期结果对比
action.andExpect(ok);
}
响应成功返回消息跟上面发送请求一样,都是调用controller打印一句话,我们看一下响应失败返回的结果。
我们将uri=/books改为/books1,程序就不到映射地址报404,而预期的是200.
3.4 响应体匹配(json数据格式,开发中的主流)
@Test
public void testJson(@Autowired MockMvc mvc) throws Exception {
//创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
//执行请求
ResultActions action = mvc.perform(builder);
//匹配执行状态(是否预期值)
//定义执行状态匹配器
ContentResultMatchers content = MockMvcResultMatchers.content();
ResultMatcher result = content.json("{\"id\":1,\"name\":\"hx\",\"desc\":\"love\"}");
//使用本次真实值与预期结果对比
action.andExpect(result);
}
结果我们就不看了
3.5 响应头匹配
@Test
public void testHeader(@Autowired MockMvc mvc) throws Exception {
//创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
//执行请求
ResultActions action = mvc.perform(builder);
//匹配执行状态(是否预期值)
//定义执行状态匹配器
HeaderResultMatchers header = MockMvcResultMatchers.header();
ResultMatcher string = header.string("Content-Type", "application/json");
//使用本次真实值与预期结果对比
action.andExpect(string);
}
3.6 完整信息匹配
有了响应状态,响应头,响应体,我们就可以完成一次完整的信息匹配了。
@Test
public void testGetById(@Autowired MockMvc mvc) throws Exception {
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books");
ResultActions action = mvc.perform(builder);
StatusResultMatchers status = MockMvcResultMatchers.status();
ResultMatcher ok = status.isOk();
action.andExpect(ok);
HeaderResultMatchers header = MockMvcResultMatchers.header();
ResultMatcher string = header.string("Content-Type", "application/json");
action.andExpect(string);
ContentResultMatchers content = MockMvcResultMatchers.content();
ResultMatcher result = content.json("{\"id\":1,\"name\":\"hx\",\"desc\":\"love\"}");
action.andExpect(result);
}
4. 数据层测试数据回滚
测试用例如果测试时产生了事务提交就会在测试过程中对数据库数据产生影响,进而产生垃圾数据。这个过程不是我们希望发生的,作为开发者测试用例该运行运行,但是过程中产生的数据不要在我的系统中留痕,这样该如何处理呢?
springboot早就为开发者想到了这个问题,并且针对此问题给出了最简解决方案,在原始测试用例中添加注解@Transactional即可实现当前测试用例的事务不提交。当程序运行后,只要注解@Transactional出现的位置存在注解@SpringBootTest,springboot就会认为这是一个测试程序,无需提交事务,所以也就可以避免事务的提交。
@SpringBootTest
@Transactional
@Rollback(true)
public class DaoTest {
@Autowired
private BookService bookService;
@Test
void testSave(){
Book book = new Book();
book.setName("springboot3");
book.setType("springboot3");
book.setDescription("springboot3");
bookService.save(book);
}
}
如果想进行事务提交,我们就可以使用rollBack注解将其设置为false,这样事务就可以进行提交了。
总结
- 在springboot的测试类中通过添加注解@Transactional来阻止测试用例提交事务
- 通过注解@Rollback控制springboot测试类执行结果是否提交事务,需要配合注解@Transactional使用
5. 测试用例数据设定
对于测试用例的数据固定书写肯定是不合理的,springboot提供了在配置中使用随机值的机制,确保每次运行程序加载的数据都是随机的。具体如下:
前配置就可以在每次运行程序时创建一组随机数据,避免每次运行时数据都是固定值的尴尬现象发生,有助于测试功能的进行。数据的加载按照之前加载数据的形式,使用@ConfigurationProperties注解即可
@Component
@Data
@ConfigurationProperties(prefix = "testcase.book")
public class BookCase {
private int id;
private String name;
private String type;
private String description;
}
使用随机产生的数据进行测试