使用JUnit对Spring Boot中的Rest Controller进行单元测试

1. 提供GET请求方法

在UserController类中,我们将提供如下几个公开的GET请求方法:

  • @GetMapping(value="/users") : 获取所有的用户信息
  • @GetMapping(value="/users/{id}/roles") : 根据用户ID获取该用户的所有角色信息

UserController.java类中的详细代码如下:

package com.ramostear.spring.boot.test.restservice.controller;

import com.ramostear.spring.boot.test.restservice.model.Role;
import com.ramostear.spring.boot.test.restservice.model.User;
import com.ramostear.spring.boot.test.restservice.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class UserController {
    private  final UserService userService;

    @Autowired
    public UserController(UserService userService){
        this.userService = userService;
    }

    @GetMapping(value = "/users")
    public List findAllStudents(){
        return userService.findAllUsers();
    }

    @GetMapping(value = "/users/{id}/roles")
    public List findUserRoles(@PathVariable(value = "id")String id){
        return userService.findUserAllRoles(id);
    }

}

2. 为RestController编写单元测试

 

当我们需要对一个Rest Controller进行单元测试时,我们只想启动和SpringMVC相关的组件,而不必要启动所有的Web组件。我们可以使用WebMvcTest注解来解决这样的测试需求。此注解将禁用Spring Boot的自动化配置,仅仅启动与MVC相关的配置。下面将对测试用例中的几个核心注解做一下介绍:

  • @RunWith(SpringRunner.class) : SpringRunner是SpringJUnit4ClassRunner的简写,它扩展了BlockJUnit4ClassRunner类,用于提供测试时的Spring应用上下文信息。
  • @WebMvcTest(value=UserController.class,secure = false) : 该注解用于测试Spring MVC应用程序,使用此注解的好处是我们只需要加载UserController类并对其中的方法进行单元测试,而不需要加载其他的控制器。
  • MockMvc : MockMvc是测试Spring MVC应用程序的主要入口,它将为我们的测试提供一个模拟的应用上下文环境。
  • @MockBean : MockBean主要是模拟向Spring应用上下文注入一个Bean对象,并使该Bean对象可以在控制器中被访问到。

下面是测试用例的源代码:

package com.ramostear.spring.boot.test.restservice;

import com.ramostear.spring.boot.test.restservice.controller.UserController;
import com.ramostear.spring.boot.test.restservice.model.Role;
import com.ramostear.spring.boot.test.restservice.model.User;
import com.ramostear.spring.boot.test.restservice.service.UserService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.skyscreamer.jsonassert.JSONAssert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@WebMvcTest(value = UserController.class,secure = false)
public class UserControllerTests {
    private static Logger logger = LoggerFactory.getLogger(UserControllerTests.class);
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    public void findAllUsers() throws Exception{
        User user = new User();
        user.setId("1001");
        user.setName("ramostear");
        user.setAlias("谭朝红");

        Role role = new Role();
        role.setId("1001");
        role.setName("admin");
        role.setDescription("all permissions for this role.");
        List roles = new ArrayList<>();
        roles.add(role);
        user.setRoles(roles);
        List users = new ArrayList<>();
        users.add(user);

        Mockito.when(userService.findAllUsers()).thenReturn(users);
        RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/users");
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        String expected = "[{\"id\":\"1001\",\"name\":\"ramostear\",\"alias\":\"谭朝红\",\"roles\":[{\"id\":\"1001\",\"name\":\"admin\",\"description\":\"all permissions for this role.\"}]}]";
        logger.info(result.getResponse().getContentAsString());
        JSONAssert.assertEquals(expected,result.getResponse().getContentAsString(),false);
    }

    @Test
    public void findAllUserRoles() throws Exception{
        Role role = new Role();
        role.setId("1001");
        role.setName("admin");
        role.setDescription("all permissions for this role.");
        List roles = new ArrayList<>();
        roles.add(role);
        Mockito.when(userService.findUserAllRoles("1001")).thenReturn(roles);
        RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/users/1001/roles");
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        String expected = "[{\"id\":\"1001\",\"name\":\"admin\",\"description\":\"all permissions for this role.\"}]";
       logger.info(result.getResponse().getContentAsString());
        JSONAssert.assertEquals(expected,result.getResponse().getContentAsString(),false);
    }
}
Mockito.when().thenReturn():用于测试UserService在被调用时是否返回和预期一致的结果

mockMvc.perform().andReturn():mockMvc主要用于执行请求并返回响应数据

下面我们执行上述两个方法,看看测试结果:

使用JUnit对Spring Boot中的Rest Controller进行单元测试_第1张图片

两个方法均测试通过,且控制台也输出了如下的日志信息:

2019-05-10 05:36:40.567  INFO 18268 --- [           main] c.r.s.b.t.r.UserControllerTests          : [{"id":"1001","name":"admin","description":"all permissions for this role."}]
2019-05-10 05:36:40.585  INFO 18268 --- [           main] c.r.s.b.t.r.UserControllerTests          : [{"id":"1001","name":"ramostear","alias":"谭朝红","roles":[{"id":"1001","name":"admin","description":"all permissions for this role."}]}]

3. 添加POST请求方法

现在我们在Rest Controller中新增一个为用户添加新角色的方法,当角色被成功设置后将返回状态码为201的一个创建资源状态。代码如下:

 @PostMapping(value = "/users/{id}")
    public ResponseEntity setUserRole(@PathVariable(value = "id")String id, @RequestBody Role role){
        userService.addUserRole(id,role);
        return new ResponseEntity<>(role, HttpStatus.CREATED);
    } 
  

 

4. 为Post方法提供单元测试用例

在接下来的测试中,我们将使用MockMvcRequestBuilders.post()方法来模拟请求添加用户角色的方法,并使用accept()方法来设置数据格式,另外还需断言请求响应的状态值是否为CREATED且返回的角色信息是否与预期的一致。Post方法的测试源码如下:

@Test
    public void addUserRole() throws Exception{
        String JSON = "{\"id\":\"1002\",\"name\":\"editor\",\"description\":\"content editor\"}";
        RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/users/1001")
                .accept(MediaType.APPLICATION_JSON).content(JSON)
                .contentType(MediaType.APPLICATION_JSON);
        MvcResult result = mockMvc.perform(requestBuilder).andReturn();
        MockHttpServletResponse response = result.getResponse();
        Assert.assertEquals(HttpStatus.CREATED.value(),response.getStatus());
        String expected = "{\"id\":\"1002\",\"name\":\"editor\",\"description\":\"content editor\"}";
        logger.info(result.getResponse().getContentAsString());
        JSONAssert.assertEquals(expected,result.getResponse().getContentAsString(),false);
    }

最后,我们执行此测试用例方法,观察测试结构:

使用JUnit对Spring Boot中的Rest Controller进行单元测试_第2张图片

通过图我们可以看到,Post方法已成功通过测试。

 

你可能感兴趣的:(软件测试)