如何使用 Mockito 和 JUnit 在 Spring Boot 中测试 POST 方法

Posted

技术标签:

【中文标题】如何使用 Mockito 和 JUnit 在 Spring Boot 中测试 POST 方法【英文标题】:How to test POST method in Spring boot using Mockito and JUnit 【发布时间】:2018-12-23 02:43:11 【问题描述】:

我是在 Spring Boot 框架中使用 JUnit 和 Mockito 进行单元测试的新手。 我想测试这个方法。如何测试 POST 请求方法:

// add Employee
@RequestMapping(method = RequestMethod.POST)
public void addEmployee(@RequestBody Employee employee)
    this.employeeService.addEmployee(employee);

提前谢谢你

【问题讨论】:

用两个词:@WebMvcTest 编写单元测试,@MockBean 模拟依赖项。 您可能想查看MockMvc 【参考方案1】:

正如@merve-sahin 正确指出的那样,您可以使用@WebMvcTest 来实现这一点。

看下面的例子:

@RunWith(SpringRunner.class)
@WebMvcTest(YourController.class)
public class YourControllerTest 

    @Autowired MockMvc mvc;
    @MockBean EmployeeService employeeService;

    @Test
    public void addEmployeeTest() throws Exception 

        Employee emp = createEmployee();

        mvc.perform(post("/api/employee")
            .contentType(MediaType.APPLICATION_JSON)
            .content(toJson(emp)))
            .andExpect(status().isOk());
    

在上面的代码中,您可以使用@MockBean 模拟您的依赖服务。 测试将在您的自定义 Employee 对象上执行发布并验证响应

可以在调用perform时添加headers、授权

假设您使用 JSON 作为媒体类型,您可以使用任何 json 库编写 toJson() 方法将 Employee 对象转换为 Json 字符串格式

private String toJson(Employee emp) 

如果你使用的是 XML,那么你可以对 XML 做同样的事情

您可以使用期望以链式方式验证响应。 正如正确指出的那样,请查看 MockedMvc​​ 链接,这应该对您有所帮助

【讨论】:

你能解释一下 emp 对象会发生什么,以及如何仅仅创建它就足以测试后续帖子?还有 createEmployee 是什么样子的?【参考方案2】:

通过以下示例:

@RunWith(SpringJUnit4ClassRunner.class)
public class ApplicationControllerTest 

    @Mock
    EmployeeService employeeService;

    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception 
        initMocks(this);
        YourController controller = new YourController(employeeService);
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    

    @Test
    public void addEmployee() throws Exception 
        Employee emp = new Employee("emp_id","emp_name");//whichever data your entity class have

        Mockito.when(employeeService.addEmployee(Mockito.any(Employee.class))).thenReturn(emp);

        mockMvc.perform(MockMvcRequestBuilders.post("/employees")
                .content(asJsonString(emp))
                .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"));
    

    public static String asJsonString(final Object obj) 
        try 
            return new ObjectMapper().writeValueAsString(obj);
         catch (Exception e) 
            throw new RuntimeException(e);
        
    

在上面给出的示例中模拟您的服务类,这是将数据发布到您的 Employee 实体类所需的。 我假设您是通过控制器执行此操作的,因此您首先需要初始化 @Before 注释下的控制器。

通过上述示例,您将能够将数据发布为 JSON 格式。

【讨论】:

【参考方案3】: 以下示例使用 JUnit5、Mockito3.x、spring-boot2.4.4 和 assertj3.x 2.2.0 版的 spring-boot-starter-test 依赖项 Junit 5 已经附带,并且还包含 Hamcrest、assertj 和 Mockito 库。 在 JUnit 5 中,JUnit 4 中可用的“Runner”扩展点被扩展 API 取代。 您可以通过 @ExtendWith 注册 Mockito 扩展。 初始化带有 @Mock 注释的模拟,这样就不需要显式使用 MockitoAnnotations#initMocks(Object)。 从 spring-boot 2.1 开始,无需使用注解 @ExtendWith 加载 SpringExtension,因为它作为元注解包含在这些注解 @DataJpaTest、@WebMvcTest 和 @SpringBootTest 中。

带有 Github 链接的完整示例:https://github.com/jdamit/DemoSpringBootApp.git

**@WebMvcTest(controllers = UserController.class)**

public class UserControllerTest 

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper mapper;

    @MockBean
    private UserServiceImpl userService;

    private List<UserDto> users;

    private UserDto user;

    private String URI = "/users";

    @BeforeEach
    void setUp()
        users = List.of(new UserDto("Amit", "Kushwaha", "jdamit2027@gmail.com", "sector 120"),
                new UserDto("Amit", "Kushwaha", "jdamit2027@gmail.com", "sector 120"),
                new UserDto("Amit", "Kushwaha", "jdamit2027@gmail.com", "sector 120"));
        user = new UserDto("Rahul", "Swagger", "rahul.swagger@gmail.com", "sector 120");
    

    @Test
    //@Disabled
    void getUsersTest() throws Exception 

        Mockito.when(userService.getUsers()).thenReturn(users);

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get(URI)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk())
                .andReturn();

        Assertions.assertThat(result).isNotNull();
        String userJson = result.getResponse().getContentAsString();
        Assertions.assertThat(userJson).isEqualToIgnoringCase(mapper.writeValueAsString(users));
    

    @Test
    //@Disabled
    void createUserTest() throws Exception 

        Mockito.when(userService.createUser(Mockito.any(UserDto.class))).thenReturn(user);

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post(URI)
                .contentType(MediaType.APPLICATION_JSON)
                .content(mapper.writeValueAsString(user).getBytes(StandardCharsets.UTF_8))
                .accept(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk())
                .andReturn();

        Assertions.assertThat(result).isNotNull();
        String userJson = result.getResponse().getContentAsString();
        Assertions.assertThat(userJson).isNotEmpty();
        Assertions.assertThat(userJson).isEqualToIgnoringCase(mapper.writeValueAsString(user));
    

【讨论】:

以上是关于如何使用 Mockito 和 JUnit 在 Spring Boot 中测试 POST 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 mockito 和 junit 测试此功能?

如何在没有 maven 的情况下设置独立的 Junit 和 Mockito

如何使用mockito和junit为Java中的ExecutorService编写测试用例?

如何使用 mockito 为以下代码编写 junit 测试?

如何使用junit和mockito为私有void方法编写测试用例[重复]

如何在 JUnit Test Java 中替换 Mockito 以存根类