使用MockMVC测试Spring Boot的REST用例

18-11-28 banq
    

MockMVC类是Spring MVC测试框架的一部分,它通过启动一个Servlet容器帮助测试REST控制器。

在这个MockMVC教程中,我们将使用它和Spring boot的WebMvcTest类来执行Junit测试用例,该测试用例测试为Spring boot 2 hateoas编写的REST控制器方法。

Maven依赖:

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

一个JUnit测试类来测试Spring MVC控制器请求和响应,我们可以使用下面给出的配置。

@RunWith(SpringRunner.class)
@WebMvcTest(EmployeeRESTController.class)
public class TestEmployeeRESTController {
 
  @Autowired
  private MockMvc mvc;
 
}

  • SpringRunner是SpringJUnit4ClassRunner别名。它是JUnit的BlockJUnit4ClassRunner的自定义扩展,它通过TestContextManager和相关的支持类和注释为标准JUnit测试提供Spring TestContext Framework的功能。
  • @WebMvcTest注释用于Spring MVC测试。它禁用完全自动配置,而只应用与MVC测试相关的配置。
  • WebMvcTest注释将自动配置MockMvc实例。
  • 使用EmployeeRESTController.classas参数,我们要求只初始化一个Web控制器,您需要使用Mock对象提供所需的剩余依赖项。

HTTP GET

假设有一个Rest控制器:

@GetMapping(value = "/employees")
public EmployeeListVO getAllEmployees()
{
    //code
}
 
@GetMapping(value = "/employees/{id}")
public ResponseEntity<EmployeeVO> getEmployeeById (@PathVariable("id") int id)
{
    //code
}

下面给出了相应的方法测试:

@Autowired
private MockMvc mvc;
 
@Test
public void getAllEmployeesAPI() throws Exception
{
  mvc.perform( MockMvcRequestBuilders
      .get("/employees")
      .accept(MediaType.APPLICATION_JSON))
      .andDo(print())
      .andExpect(status().isOk())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employees").exists())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employees<li>.employeeId").isNotEmpty());
}
 
@Test
public void getEmployeeByIdAPI() throws Exception
{
  mvc.perform( MockMvcRequestBuilders
      .get("/employees/{id}", 1)
      .accept(MediaType.APPLICATION_JSON))
      .andDo(print())
      .andExpect(status().isOk())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employeeId").value(1));
}

HTTP POST

案例:

@PostMapping(value = "/employees")
public ResponseEntity<EmployeeVO> addEmployee (@Valid @RequestBody EmployeeVO employee)
{
    //code
    return new ResponseEntity<EmployeeVO>(employee, HttpStatus.CREATED);
}

对于post json请求的相应spring springmvc测试如下:

@Autowired
private MockMvc mvc;
 
@Test
public void createEmployeeAPI() throws Exception
{
  mvc.perform( MockMvcRequestBuilders
      .post("/employees")
      .content(asJsonString(new EmployeeVO(null, "firstName4", "lastName4", "email4@mail.com")))
      .contentType(MediaType.APPLICATION_JSON)
      .accept(MediaType.APPLICATION_JSON))
      .andExpect(status().isCreated())
      .andExpect(MockMvcResultMatchers.jsonPath("$.employeeId").exists());
}
 
public static String asJsonString(final Object obj) {
    try {
        return new ObjectMapper().writeValueAsString(obj);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

HTTP PUT

HTTP API在控制器中定义为:

@PutMapping(value = "/employees/{id}")
public ResponseEntity<EmployeeVO> updateEmployee (@PathVariable("id") int id, @Valid @RequestBody EmployeeVO employee)
{
    //code
    return new ResponseEntity<EmployeeVO>(emp, HttpStatus.OK);
}

相应的方法测试是

@Test
public void updateEmployeeAPI() throws Exception
{
  mvc.perform( MockMvcRequestBuilders
      .put("/employees/{id}", 2)
      .content(asJsonString(new EmployeeVO(2, "firstName2", "lastName2", "email2@mail.com")))
      .contentType(MediaType.APPLICATION_JSON)
      .accept(MediaType.APPLICATION_JSON))
      .andExpect(status().isOk())
      .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("firstName2"))
      .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("lastName2"))
      .andExpect(MockMvcResultMatchers.jsonPath("$.email").value("email2@mail.com"));
}

HTTP DELETE:

@DeleteMapping(value = "/employees/{id}")
public ResponseEntity<HttpStatus> removeEmployee (@PathVariable("id") int id)
{
    //code
    return new ResponseEntity<HttpStatus>(HttpStatus.ACCEPTED);
}

相应的方法测试是:

@Test
public void deleteEmployeeAPI() throws Exception
{
  mvc.perform( MockMvcRequestBuilders.delete("/employees/{id}", 1) )
        .andExpect(status().isAccepted());
}