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}}