需要在 POST 端点中模拟服务方法,跳过 @RequestBody 注释
Need to mock a service method in a POST endpoint skiping @RequestBody annotation
我正在尝试为 POST REST 端点编写单元测试。我需要使用 mockito 模拟在上述端点中使用的服务方法。使用 mock mvc 触发端点。
我在端点中使用 userService.saveUser(user) 和 return 一个整数作为创建的 userId 来模拟。但似乎模拟总是 returning 0 而不是 7777 (定义了 userId)。
对于 "verify",它表示 "Argument(s) are different!" 正在端点和我定义的模拟中传递给 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" 模拟的问题。(如果我错了请纠正我)
可能我必须做一些工作来触发端点并将 "user" 对象传递给 "userService" ,因为它在 Test class 中定义并跳过 @RequestBody注释。
谁能指导我解决这个问题?任何帮助将不胜感激。
端点:
@PostMapping("/users")
public ResponseEntity<String> saveUser(@RequestBody User user){
int userId = userService.saveUser(user);
return new ResponseEntity<>("User created. Id: "+ userId, HttpStatus.CREATED);
}
测试Class:
@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);
}
}
我觉得是你说的那个原因。你可以做的是使用一个匹配器传递给你的模拟,这样它就会return你想要的,只要它接收到一个特定类型的对象(而不是一个特定的对象:
import static org.mockito.ArgumentMatchers.any;
...
when(userService.saveUser(any(User.class))).thenReturn(userId);
mock,在你使用它的时候使用,它会return你想要的,只有当它接收你在做when
时传递的特定对象作为调用的参数时.正如您从异常中看到的那样,模拟期望接收一个带有引用 com.foo.dto.User@741f8dbe
的对象(这是您在 setUp 方法中创建的对象),但它正在接收 com.foo.dto.User@212dfd39
这是Jackson 在反序列化 rest 调用的主体时生成的那个。
我正在尝试为 POST REST 端点编写单元测试。我需要使用 mockito 模拟在上述端点中使用的服务方法。使用 mock mvc 触发端点。
我在端点中使用 userService.saveUser(user) 和 return 一个整数作为创建的 userId 来模拟。但似乎模拟总是 returning 0 而不是 7777 (定义了 userId)。 对于 "verify",它表示 "Argument(s) are different!" 正在端点和我定义的模拟中传递给 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" 模拟的问题。(如果我错了请纠正我)
可能我必须做一些工作来触发端点并将 "user" 对象传递给 "userService" ,因为它在 Test class 中定义并跳过 @RequestBody注释。
谁能指导我解决这个问题?任何帮助将不胜感激。
端点:
@PostMapping("/users")
public ResponseEntity<String> saveUser(@RequestBody User user){
int userId = userService.saveUser(user);
return new ResponseEntity<>("User created. Id: "+ userId, HttpStatus.CREATED);
}
测试Class:
@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);
}
}
我觉得是你说的那个原因。你可以做的是使用一个匹配器传递给你的模拟,这样它就会return你想要的,只要它接收到一个特定类型的对象(而不是一个特定的对象:
import static org.mockito.ArgumentMatchers.any;
...
when(userService.saveUser(any(User.class))).thenReturn(userId);
mock,在你使用它的时候使用,它会return你想要的,只有当它接收你在做when
时传递的特定对象作为调用的参数时.正如您从异常中看到的那样,模拟期望接收一个带有引用 com.foo.dto.User@741f8dbe
的对象(这是您在 setUp 方法中创建的对象),但它正在接收 com.foo.dto.User@212dfd39
这是Jackson 在反序列化 rest 调用的主体时生成的那个。