SpringBoot中使用MockMVC进行测试
首先得保证已经在pom中引入了以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
- 原始测试代码
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.junit.Assert.*;
/**
* @Author sherry
* @Description
* @Date Create in 2019-03-13
* @Modified By:
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
@AutoConfigureMockMvc
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
}
至此,就已经构建好了MVC环境,可以模拟Web环境进行测试了
基本Get请求
@Test
public void testQuerySuccess() throws Exception {
// perform:发起请求,然后判断返回结果是否符合我们的期望
mockMvc.perform(MockMvcRequestBuilders.get("/user/")
.contentType(MediaType.APPLICATION_JSON_UTF8))
// 要求返回结果状态码为 200
.andExpect(MockMvcResultMatchers.status().isOk())
// 要求返回结果是一个集合,且长度为3
.andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3));
}
此时直接执行Test方法,毫无疑问返回状态码为404,因为我还没有编写/user/
接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mIinp1SC-1586610601923)(https://ws3.sinaimg.cn/large/006tKfTcly1g11etrmg17j30se0rs1b9.jpg)]
- 完善Controller
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping
public ResponseEntity getUserList() {
List<UserVo> list = Arrays.asList(new UserVo().setName("哇哈哈1")
, new UserVo().setName("哇哈哈2")
, new UserVo().setName("哇哈哈3"));
return ResponseEntity.ok(list);
}
}
这样测试用例就能通过了
这里的Vo对象,使用lombok进行了便捷操作
@Test
public void whenGetInfoFail() throws Exception {
mockMvc.perform(get("/user/a")
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().is4xxClientError());
}
指定返回的是4xx的错误码
添加Param请求参数
@Test
public void testQuerySuccess() throws Exception {
// perform:发起请求,然后判断返回结果是否符合我们的期望
mockMvc.perform(MockMvcRequestBuilders.get("/user/")
// 添加请求参数
.param("name", "小混蛋")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
// 要求返回结果状态码为 200
.andExpect(MockMvcResultMatchers.status().isOk())
// 要求返回结果是一个集合,且长度为3
.andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(3));
}
在Controller中,使用同名基本类型参数,或者带有此名的POJO对象进行接收即可
在andExpect
中编写期望;一般先判断状态,再判断内容
- Controller中的代码
public ResponseEntity getUserList(@RequestParam String name)
或
public ResponseEntity getUserList(UserQueryCondition userQueryCondition)
只要保证查询对象中有name
成员变量即可
注意,查询对象前不能添加@RequestParam注解
分页查询
如果使用Spring Data项目作为持久层,那么可以使用Pageable
对象来接收分页信息,参数名默认为page
、size
.param("page","3")
.param("size","15")
public ResponseEntity getUserList(UserQueryCondition userQueryCondition
, Pageable pageable)
使用@PageableDefault
指定默认分页信息与排序信息
@PageableDefault(page = 0,size = 15,sort = {"name,desc"}) Pageable pageable
JsonPath表达式
对于返回结果,我们可以使用jsonPath表达式进行灵活的断言,
如MockMvcResultMatchers.jsonPath("$.length()").value(3)
,断言返回结果为长度为3的数组
.andExpect(jsonPath("$.name").value("姓名1"))
,返回的是一个对象,其中name属性值为姓名1
请求JSON对象
如果请求参数不是键值对,而是json对象,那该怎么做呢?
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.content(Json字符串)
文件上传
@Test
public void whenUploadSuccess() throws Exception {
String result = mockMvc.perform(fileUpload("/file")
.file(new MockMultipartFile("file", "test.txt", "multipart/form-data", "hello upload".getBytes("UTF-8"))))
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
System.out.println(result);
}
- Controller
private String folder = "/Users/zhangliuning/Gitee/workspace/imooc-security/imooc-security-demo/target";
@PostMapping
public FileInfo upload(MultipartFile file) throws Exception {
System.out.println(file.getName());
System.out.println(file.getOriginalFilename());
System.out.println(file.getSize());
File localFile = new File(folder, new Date().getTime() + ".txt");
file.transferTo(localFile);
return new FileInfo(localFile.getAbsolutePath());
}