测试Controller

一、背景介绍

在进行集成测试时,希望能够对Controller进行测试,如果通过启动服务器,建立 HTTP Client 进行测试,这样会使得测试变得很麻烦,比如,启动速度慢,测试验证不方便,依赖网络环境等,这样会导致测试无法进行,为了可以对 Controller 进行测试,可以通过引入 MockMVC 进行解决。

MockMvc 实现了对 HTTP 请求的模拟,能够直接使用网络的形式,转换到 Controller 的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。

二、MockMvc 使用

2.1 构建 MockMvc

通过 MockMvcBuilder 可以构建 MockMvc 对象,它主要有如下两个实现:

  • StandaloneMockMvcBuilder: 独立安装测试

    private MockMvc mockMvc;
    @BeforeEach
    public void setUp() {
    	mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
    }        
    
  • DefaultMockMvcBuilder:集成 Web 服务测试 ,建议使用这种方式

    @Autowired
    private WebApplicationContext context;
    private MockMvc mockMvc;
    @BeforeEach
    public void setUp() {
    	mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }  
    

2.2 构建请求

通过 MockMvcRequestBuilders 来构建请求,它有以下方法:

  • get
  • post
  • put
  • delete
  • ......

2.3 执行请求

MockMvc 通过调用 perform(RequestBuilder requestBuilder) 方法发起请求,将会返回一个操作结果 ResultActions

2.4 操作结果处理

ResultActions有以下三种处理:

  • ResultActions.andExpect:添加执行完成后的断言。添加 ResultMatcher 验证规则,验证控制器执行完成后结果是否正确;

  • ResultActions.andDo:添加一个结果处理器,如使用 .andDo(MockMvcResultHandlers.print()) 输出整个响应结果信息,可以在调试的时候使用。

  • ResultActions.andReturn:表示执行完成后返回相应的结果

2.5 MvcResult

执行完控制器后得到的整个结果,并不仅仅是返回值,其包含了测试时需要的所有信息。

* MockHttpServletRequest getRequest():得到执行的请求;
* MockHttpServletResponse getResponse():得到执行后的响应;
* Object getHandler():得到执行的处理器,一般就是控制器;
* HandlerInterceptor[] getInterceptors():得到对处理器进行拦截的拦截器;
* ModelAndView getModelAndView():得到执行后的ModelAndView;
* Exception getResolvedException():得到HandlerExceptionResolver解析后的异常;
* FlashMap getFlashMap():得到FlashMap;
* Object getAsyncResult()/Object getAsyncResult(long timeout):得到异步执行的结果;

三、实例

3.1 引入依赖

<dependencies> 
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

3.2 Get 请求

  1. 创建 Get 请求方法
@RestController
@RequestMapping("/test")
public class TestController {


    @GetMapping("/hello")
    public String hello(String name) {
        return "hello " + name;
    }
}    
  1. 编写测试
@SpringBootTest
public class TestControllerTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @BeforeEach
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }

    @Test
    public void should_return_hello() throws Exception {
        String expectedResult = "hello MarkLogZhu";

        final String result = mockMvc.perform(
                // GET 请求
                get("/test/hello")
                        // 添加参数
                        .param("name", "MarkLogZhu")
        )
                // 断言 HTTP 返回状态是 200
                .andExpect(status().isOk())
                // 获取返回结果对象
                .andReturn()
                // 将响应值以字符串形式返回
                .getResponse().getContentAsString();

        assertThat(result, is(expectedResult));
    }
}    

3.3 POST 请求

  1. 编写 Post 请求
@RestController
@RequestMapping("/test")
public class TestController {
    
    @PostMapping("/create")
    public User create(@RequestBody CreateUserCommand command) {
        return new User(command.getName(), command.getAge()+1);
    }

}

public class CreateUserCommand {
    private String name;
    private Integer age;

    public CreateUserCommand(){}
    public CreateUserCommand(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    ...... get/set
}   
public class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    ...... get/set    
}    

2) 编写测试

@SpringBootTest
public class TestControllerTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @BeforeEach
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
    }
    @Test
    public void should_create_user_success() throws Exception {
        String expectedResult = "{"name":"MarkLogZhu","age":19}";

        String requestJson = "{"name":"MarkLogZhu","age":18}";

        final String result = mockMvc.perform(
                // POST 请求
                post("/test/create")
                        // 设置请求内容格式为JSON
                        .contentType(MediaType.APPLICATION_JSON)
                        // 请求内容
                        .content(requestJson)
        )
                // 获取返回结果对象
                .andReturn()
                // 将响应值以字符串形式返回
                .getResponse()
                .getContentAsString();

        assertThat(result, is(expectedResult));
    }

}    
原文地址:https://www.cnblogs.com/markLogZhu/p/13685579.html