使用API为我的Web应用编写一些测试,测试控制器方法。控制器使用我要模拟的服务方法。
测试代码:
@Mock
private UserService userService;
@Mock
private PasswordEncoder passwordEncoder;
@InjectMocks
private UserApi userApi;
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(userApi).build();
@Test
public void addUser() throws Exception {
Role role = new Role(1L, "ROLE_USER");
User user = new User (null, "Test user", "Test password", true, role);
when(roleService.findByName(role.getName())).thenReturn(role);
when(passwordEncoder.encode(user.getPassword())).thenReturn("Encoded password");
when(userService.save(user)).thenReturn(1L);
mockMvc.perform(MockMvcRequestBuilders.post("/user").content(user.toJson())).andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType("application/json"))
.andExpect(content().string(user.toJson()));
}
调用UserService.save(user)时,如果为null,则将user的id属性设置为某个唯一的Long值。我可以像真实的save()一样设置UserService.save(user)的Mock来更改已保存用户的ID吗?
与PasswordEncoder相同,当调用PasswordEncoder.encode(string)时,它将字符串值更改为编码值,怎么说PasswordEncoder的模拟功能也一样?
最佳答案
想要这是一种测试气味,可能意味着您测试过多。因此,我不推荐它。您的单元测试正在测试Spring控制器,而不是在测试UserService
或PasswordEncoder
,并且不是确保用户ID更改或密码已更改的Spring控制器的职责。编码。您可以验证是否同时调用了userService
和passwordEncoder
,但这仅是测试控制器应进行的工作。
听起来您真正想做的不是模拟UserService
和PasswordEncoder
,而是对真实的类(例如在测试数据库中)执行端到端测试。您可以从控制器开始发布新用户,然后从测试数据库取回新用户,并验证您的结果是否正确。在这种情况下,您不是对Spring控制器进行单元测试,而是对整个真实链进行单元测试。
也就是说,您可以通过使用thenAnswer
而不是thenReturn
设置自定义答案来完成您要问的事情:
when(userService.save(user)).thenAnswer(new Answer<Long>() {
@Override
public Long answer(InvocationOnMock invocation) {
user.setId(1L);
return 1L;
}
});
在模拟上调用该方法时,将调用此自定义答案。其结果将是模拟方法返回的结果。在此,它还会在返回之前设置用户的ID。这仍然是非常可怕的,并且进行适当的集成测试将是更可取的。
关于java - 在方法时使用模拟,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39507627/