Mock介绍
在面向对象的程序设计中,模拟对象(英语:mock object)是以可控的方式模拟真实对象行为的假对象。在编程过程中,通常通过模拟一些输入数据,来验证程序是否达到预期结果。
为什么使用Mock对象
我们在开发过程中经常使用Postman进行接口测试,为什么还需要使用Mock对象做单元测试?因为Mock对象是一个模拟对象,可以模拟复杂的、真实的对象行为。如果在单元测试中无法使用真实对象,可采用模拟对象进行替代。
Mockito操作步骤
1、模拟测试类所需的外部依赖
2、执行测试代码
3、判断执行结果是否达到预期
MockMvc
MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。
接口MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc。主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。MockMvcBuilders提供了对应的创建方法standaloneSetup方法和webAppContextSetup方法,在使用时直接调用即可。
代码演示
1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
2、编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
@ActiveProfiles("test")
public class UserControllerTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before //在每个方法执行之前执行一遍
public void setup() {
// 实例化方式一
// mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
// 实例化方式二
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
private byte[] toJson(final Object r) throws Exception {
ObjectMapper map = new ObjectMapper();
String str = map.writeValueAsString(r);
return str.getBytes();
}
/*
* 1、mockMvc.perform执行一个请求。
* 2、MockMvcRequestBuilders.get("XXX")构造一个请求。
* 3、ResultActions.param添加请求传值
* 4、ResultActions.secure(true)设置安全校验
* 5、ResultActions.accept(MediaType.TEXT_HTML_VALUE)设置返回类型
* 6、ResultActions.andExpect添加执行完成后的断言。
* 7、ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情
* 比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息。
* 8、ResultActions.andReturn表示执行完成后返回相应的结果。
*/
@Test
@Transactional
@Rollback
public void testQueryUserById200() throws Exception {
int id = 2;
String responseString = this.mockMvc.perform(MockMvcRequestBuilders.get("/user/queryUserById/"+id)
.accept(MediaType.APPLICATION_JSON_VALUE)
.secure(false))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
System.out.println("--------返回的json = " + responseString);
}
@Test
@Transactional
@Rollback
public void testQueryUserById404() throws Exception {
int id = 2;
String responseString = this.mockMvc.perform(MockMvcRequestBuilders.get("/queryUserById/"+id) //测试url错误报错404
.accept(MediaType.APPLICATION_JSON_VALUE)
.secure(false))
.andExpect(MockMvcResultMatchers.status().isNotFound())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
System.out.println("--------返回的json = " + responseString);
}
@Test
@Transactional
@Rollback //事务操作会被回滚,可以通过设置@Rollback(value = false)使事务不回滚
public void testCreateUser200() throws Exception {
User user = new User();
user.setUsername("Zhangsan");
user.setPassword("123456");
user.setName("张三");
user.setSex("男");
user.setAddress("广东深圳");
user.setPhone("13809679020");
String responseString = this.mockMvc.perform(MockMvcRequestBuilders.post("/user/createUser/")
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(toJson(user))
.accept(MediaType.APPLICATION_JSON_VALUE)
.secure(false))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
System.out.println("--------返回的json = " + responseString);
}
@Test
@Transactional
@Rollback
public void testUpdateUser200() throws Exception {
int id = 2;
String token = "Token20210531";
User user = new User();
user.setUsername("Zhangsan");
user.setPassword("123456");
user.setName("张三");
user.setSex("男");
user.setAddress("广东深圳");
user.setPhone("13809679020");
String responseString = this.mockMvc.perform(MockMvcRequestBuilders.post("/user/updateUser/"+id)
.header("token",token)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(toJson(user))
.accept(MediaType.APPLICATION_JSON_VALUE)
.secure(false))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
System.out.println("--------返回的json = " + responseString);
}
@Test
@Transactional
@Rollback
public void testDeleteUser200() throws Exception {
int id = 2;
String responseString = this.mockMvc.perform(MockMvcRequestBuilders.delete("/user/deleteUser/"+id)
.accept(MediaType.APPLICATION_JSON_VALUE)
.secure(false))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
System.out.println("--------返回的json = " + responseString);
}
@Test
@Transactional
@Rollback
public void testDeleteUser405() throws Exception {
int id = 2;
String responseString = this.mockMvc.perform(MockMvcRequestBuilders.post("/user/deleteUser/"+id) //这里应该是delete请求,测试请求方法错误报错405
.accept(MediaType.APPLICATION_JSON_VALUE)
.secure(false))
.andExpect(MockMvcResultMatchers.status().isMethodNotAllowed())
.andDo(MockMvcResultHandlers.print())
.andReturn().getResponse().getContentAsString();
System.out.println("--------返回的json = " + responseString);
}
}
3、测试结果打印
MockHttpServletRequest:
HTTP Method = GET
Request URI = /user/queryUserById/2
Parameters = {}
Headers = [Accept:"application/json"]
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.api.controller.UserController
Method = com.api.controller.UserController#queryUserResultById(int)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json"]
Content type = application/json
Body = {"code":0,"message":"success","object":{xxx}}
Forwarded URL = null
Redirected URL = null
Cookies = []
--------返回的json = {"code":0,"message":"success","object":{xxx}}