【问题标题】:Need to mock a service method in a POST endpoint skiping @RequestBody annotation需要在 POST 端点中模拟服务方法,跳过 @RequestBody 注释
【发布时间】:2019-04-05 13:09:23
【问题描述】:

我正在尝试为 POST REST 端点编写单元测试。我需要使用 mockito 模拟在上述端点中使用的服务方法。使用 mock mvc 触发端点。

我正在模拟端点中使用的 userService.saveUser(user) 并返回一个整数作为创建的 userId。但似乎模拟总是返回 0 而不是 7777(定义的用户 ID)。 对于“验证”,它说“参数不同!”在端点和我定义的模拟中传递给 userService(user)。

Mockito 验证错误:

Argument(s) are different! Wanted:
userService.saveUser(
    com.foo.dto.User@741f8dbe
);
-> at com.foo.controller.UserControllerTest.saveUser(UserControllerTest.java:104)
Actual invocation has different arguments:
userService.saveUser(
    com.foo.dto.User@212dfd39
);
-> at com.foo.controller.UserController.saveUser(UserController.java:45)

Comparison Failure:  <Click to see difference>

我猜这是因为@RequestBody 注解创建了一个全新的用户对象。 这会导致无法使用“userService”模拟的问题。(如果我错了,请纠正我)

可能我必须做一些工作来触发端点并将“用户”对象传递给“用户服务”,因为它是在测试类中定义的,并跳过@RequestBody 注释。

谁能指导我解决这个问题?任何帮助将不胜感激。

端点:

@PostMapping("/users")
public ResponseEntity<String> saveUser(@RequestBody User user){

    int userId = userService.saveUser(user);

    return new ResponseEntity<>("User created. Id: "+ userId, HttpStatus.CREATED);
}

测试类:

@RunWith(SpringJUnit4ClassRunner.class)
public class UserControllerTest {
    @InjectMocks
    private UserController userController;
    @Mock
    private UserService userService;
    private ObjectMapper mapper;
    private MockMvc mockMvc;
    private Integer userId = 7777;

    @Before
    public void setUp() throws Exception{
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
        mapper = new ObjectMapper();

        user = new User();
        user.setName("DummyUser");
    }

    @Test
    public void saveUser(){
        when(userService.saveUser(user)).thenReturn(userId);
        this.mockMvc.perform(post("/users")
                .accept(MediaType.TEXT_PLAIN)
                .contentType(MediaType.APPLICATION_JSON)
                .content(mapper.writeValueAsString(user)))
                .andExpect(status().isCreated())
                .andExpect(content()
                       .contentTypeCompatibleWith(MediaType.TEXT_PLAIN))
                .andExpect(content().string("User created. Id: "+userId));
        verify(userService).saveUser(user);
    }

}

【问题讨论】:

    标签: spring-boot junit mockito mockmvc


    【解决方案1】:

    我想原因就是你说的那个。您可以做的是使用匹配器传递给您的模拟,因此只要它接收到特定类型的对象(而不是特定对象:

    import static org.mockito.ArgumentMatchers.any;
    ...
    when(userService.saveUser(any(User.class))).thenReturn(userId);
    

    模拟,在您使用它时使用,只有当它作为调用的参数接收您在执行when 时传递的特定对象时,它才会返回您想要的内容。正如您从异常中看到的那样,模拟期望接收一个引用 com.foo.dto.User@741f8dbe 的对象(这是您在 setUp 方法中创建的对象),但它正在接收 com.foo.dto.User@212dfd39 这是由Jackson 反序列化 rest 调用的主体。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-03
      • 1970-01-01
      • 1970-01-01
      • 2020-05-19
      • 2018-10-12
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      相关资源
      最近更新 更多