构建在Spring测试框架之上
提供一组用于测试的注解和工具
@SpringBootTest @MockBean
@WebMvcTest @WebFluxTest
@DataJpaTest @DataJdbcTest @JdbcTest @DataMongoTest @DataRedisTest
如何开始?添加Spring Boot测试的Starter使用spring-boot-starter-test的测试依赖项,其中包含org.springframework.boot spring-boot-starter-testtest
JUnit:默认版本是5(从Spring boot 2.2版本开始)
Spring Test和Spring Boot Test 测试注解
AssertJ: 一个断言库
Hamcrest:一个匹配库
Mockito:一个java模拟框架
JSONassert:一个用于JSON的断言库
JsonPath:用于JSON的XPath
使用@SpringBootTest进行集成测试自动搜索@SpringBootConfiguration
- 作为@ContextConfiguration的代替方案,用于创建测试使用的应用上下文
- 使用@SpringBootTest进行集成测试,使用@ContextConfiguration进行分片测试
提供对不同webEnvironment模式的支持
RANDOM_PORT,DEFINED_PORT,MOCK,NONE
由测试框架启动嵌入式服务器
集成测试可以作为CI/CD管道的一部分来完成
自动配置一个TestRestTemplate
用@ExtendWith(从Spring Boot2.2开始)进行元注解
使用TestRestTemplate进行集成测试方便的适宜用于集成测试的RestTemplate的代替品
- 采取相对路径(而不是绝对路径)
- 容错性:服务器应用程序收到404等错误响应时,他不会抛出一个异常
- 配置为忽略cookies和重定向
如果你需要自定义
使用RestTemplateBuilder,例如添加自定义Message Converter
使用TestRestTemplate的示例代码@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)//知道与“随机”端口对话
public class AccountClientBootTests {
@Autowired
private TestRestTemplate restTemplate;//知道与“随机”端口对话
// 测试代码
}
使用TestRestTemplate的示例代码 -- 测试代码
@Test
public void addAndDeleteBeneficiary() {
//相对路径
String addUrl = "/accounts/{accountId}/beneficiaries";
URI newBeneficiaryLocation = restTemplate.postForLocation(addUrl, "David", 1);
Beneficiary newBeneficiary= restTemplate.getForObject(
newBeneficiaryLocation,Beneficiary.class);
assertThat(newBeneficiary.getName()).isEqualTo("David");
restTemplate.delete(newBeneficiaryLocation);
ResponseEntity response= restTemplate.getForEntity(
newBeneficiaryLocation, Account.class);
//检查响应的状态码
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
}
对Spring MVC测试的需求
考虑到下面的控制器,你如何验证:
- @PutMapping的结果是一个正确的URL映射?
- @PathVariable的映射是有效的?
- 帐户从传入的JSON/XML中被正确映射?
- 返回的状态是HTTP 204?
- 是否按照预期处理了任何异常?
@PutMapping("/account/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT) // 204
public void updateOrder(@RequestBody Account account, @PathVariable long id) {
// process updated account and return empty response
accountManager.update(id, account);
}
MVC测试框架概览
Spring框架的一部分
在spring-test.jar中可以看到
目标:微测试Spring MVC代码提供一流的支持
通过DispatcherServlet处理请求
不需要运行web容器即可测试,不需要为测试代码协调服务器的URL/端口
示例:MockMvc 测试//静态导入使得调用Builder和Matcher的静态方法更加容易。
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
//定义一个MockMVC环境(不过使@WebMvcTest会更简单)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
public final class AccountControllerTests {
@Autowired
MockMvc mockMvc;
@Test
public void testBasicGet() {
//定义一个MockMVC环境(不过使@WebMvcTest会更简单)
//对mockMvc实例进行测试
mockMvc.perform(get("/accounts")).andExpect(status().isOk());
}
}
设置静态导入
静态导入是流体Builder的关键,MockMvcRequestBuilders.*和MockMvcResultMatchers.*
你可以在偏好设置中添加到Eclipse/STS的"favorite static menbers"中
- java->Editor->Content Assist->Favorites
- 添加到favorite static members
- org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
- org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
perform()的参数决定了动作
- 来自MockMvcRequestBuilders的get()(或put(),post(),等等)
- 用MockHttpServletRequestBuilders的方法进行追加
@Test
public void testRestfulGet() throws Exception {
//MockMvcRequestBuilders的方法要放在perform()里面。
mockMvc.perform(get("/accounts/{acctId}","123456001")
.accept(MediaType.APPLICATION_JSON));
…
// Continued …
}
MockMvcRequestBuilders 静态方法
标准的HTTP get,put,post,delete操作
支持文件上传
参数是一个URI模版字符串
返回一个MockHttpServletRequestBuilder实例(用于连锁其他方法)
// 使用URI模版样式提交一个GET请求
mockMvc.perform(get("/accounts/{acctId}", "123456001"))
// 使用请求参数样式提交一个GET请求
mockMvc.perform(get("/accounts?myParam={acctId}", "123456001"))
| 方法 | 描述 |
| param | 添加一个请求参数,例如:param("myParam", 123) |
| requestAttr | 添加一个对象作为请求的Attribute,另外,sessionAttr对Session作用域的对象做相同的处理 |
| header | 在请求中添加一个header的变量。另外,参考headers,它可以添加多个header |
| content | 请求体 |
| contentType | 设置请求体的Content-Type(MIME类型) |
| accept | 为预期的响应设置请求的类型(MIME类型) |
| locale | 设定提出请求的地方 |
perform()返回ResultActions对象
可以将expects链在一起,链式编程
来自MockMvcResultMatchers的content()和jsonPath();
@Test
public void testRestfulGet() throws Exception {
mockMvc.perform(
get("/accounts/{acctId}","123456001")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"));
}
返回Matchers提供的指定的断言
| 方法 | Matcher返回的 | 描述 |
| content | ContentResultMatchers | 与HTTP响应体有关的断言 |
| header | HeaderResultMatchers | HTTP headers的断言 |
| status | StatusResultMatchers | HTTP状态码的断言 |
| xpath | 使用Xpath表达式搜索返回的XML | |
| jsonPath | 使用JsonPath搜索返回的JSON |
设置Accept Header
mockMvc.perform(get("/accounts/{acctId}","123456001")
.accept("application/json") // 请求JSON响应
...
//PUTting JSON payload
mockMvc.perform(put("/accounts/{acctId}","123456001")
.content("{ ... ... }")
.contentType("application/json")
...
打印调试信息
有时候你希望知道发生了什么
andDo()在MvcResult上执行动作
print()发送MvcResult到输出流,或者使用andReturn()以获取MvcResult对象
// 使用这个以访问print()方法
import static org.springframework.test.web.servlet.result.MockMvcResult.*;
// 还有其它静态导入
// 使用print()方法在测试中获取调试信息
mockMvc.perform(get("/accounts/{acctId}", "123456001"))
.andDo(print()) // 添加这一行将调试信息打印在控制台
.andExpect(status().isOK())
…
切片测试
什么是切片测试?
在应用程序的一个切片内执行独立的测试
Web切片,储存库切片,缓存切片
各依赖项需要被模拟
使用@WebMvcTest进行切片测试- 禁用全部自动配置,只应用与MVC测试相关的配置
- 自动配置Mvc测试框架 MockMvc bean是自动配置的,还有可选的Spring Security
- 通常情况下,@WebMvcTest与@MockBean结合使用,模拟器依赖关系
//只创建与AccountController相关的bean
@WebMvcTest(AccountController.class)
public class AccountControllerBootTests {
@Autowired
private MockMvc mockMvc;
@MockBean
private AccountManager accountManager;
@Test
public void testHandleDetailsRequest() throws Exception {
// Test code
}
}
@Test
public void testHandleDetailsRequest() throws Exception {
// arrange
given(accountManager.getAccount(0L))
.willReturn(new Account("1234567890", "John Doe"));
// act and assert
mockMvc.perform(get("/accounts/0"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)
.andExpect(jsonPath("name").value("John Doe"))
.andExpect(jsonPath("number").value("1234567890"));
// verify
verify(accountManager).getAccount(0L);
}
依赖的@Mock与@MockBean
@Mock:来自Mokito框架,当不需要Spring上下文时使用它
@MockBean 来自Spring Boot框架,当需要Spring上下文时使用它
当Spring上下文中不存在模拟bean时,创建一个新的模拟bean,或者当存在模拟Bean时明一个模拟Bean替换一个Bean
使用@DataJpaTest进行存储库切片测试- 可用于测试只关注JPA组件的情况下,加载@Repository beans,不包括其他@Components
- 自动配置TestEntityManager
- 用于JPA测试的EntityManager的代替品
- 提供了EntityManager方法的一个子集
- 只对测试有用的
- 常见测试任务的辅助方法
- persistFlushFind(),persistAndFlush()
- 使用一个嵌入式内存数据库
- 取代任何显示或自动配置的数据源
- 可以使用@AutoConfigureTestDatabase注解来覆盖这些设置
@SPringBootTest扩展了测试的选项
Spring MVC测试框架提供了一个模拟的Web环境,不需要运行外部的应用服务器
Boot提供了Web分片测试,Mock MVC测试专注于特定的控制器
Boot提供JPA分片测试



