Mockito 测试期间对象引用发生变化
Object reference changing during Mockito Test
我刚开始使用 Mockito,我遇到了一个测试失败的问题,但实际代码在实时环境中运行正常。正在测试的控制器是:
@Controller
@RequestMapping("/notes")
public class NotesController {
private NoteRepository noteRepository;
private MyUserRepository userRepository;
@RequestMapping(value = "/add", method = POST)
public String postNote(@Valid Note note, BindingResult errors, Principal principal){
String username = principal.getName();
MyUser user = userRepository.findUserByUsername(username);
note.setMyUser(user);
note.setTime(new Date());
noteRepository.save(note);
return "redirect:/notes"; }
}
测试在这里:
@Test
public void testShouldAddValidNote() throws Exception {
MyUser testing = new MyUser();
Note note = new Note();
NoteRepository noteRepository = mock(NoteRepository.class);
when(noteRepository.save(note)).thenReturn(note);
MyUserRepository userRepository = mock(MyUserRepository.class);
when(userRepository.findUserByUsername("testing")).thenReturn(testing);
Principal mockPrincipal = mock(Principal.class);
when(mockPrincipal.getName()).thenReturn("testing");
NoteController controller = new NoteController(noteRepository);
controller.setMyUserRepository(userRepository);
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(post("/notes/add")
.requestAttr("note", note)
.principal(mockPrincipal))
.andExpect(view().name("redirect:/notes"));
verify(noteRepository,times(1)).save(note);
verify(note,times(1)).setMyUser(testing);
verify(note,times(1)).setTime((Date)anyObject());
verify(userRepository,times(1)).findUserByUsername("testing");
verify(mockPrincipal,times(1)).getName();
}
第一个验证测试失败,并显示消息:
Argument(s) are different! Wanted:
noteRepository.save(projectName.Note@5ae9);
Actual invocation has different arguments:
noteRepository.save(projectName.Note@c079ae45
显然传入方法的 Note 对象已经改变,但我认为使用 .requestAttr("note", note) 会传入引用,因此相同的对象应该在方法中(并且后来回来了)。就像我说的,它在实时网络容器中完美运行,请问我在 Mockito 测试中出了什么问题?
这只是一个大胆的猜测,此代码面临的问题是否来自 MockMvc
/ MockMvcRequestBuilders
,其中 Note
在请求配置和实际请求之间以某种方式序列化/反序列化?
请注意 note
是一个真实对象,因此调用 verify(note)....
将不起作用。
无论如何,我建议在这种情况下结合使用 mockito captor 和 AssertJ:
// if field instantiation if using the mockito runner / rule or MockitoAnnotations.initMocks(this)
@Captor ArgumentCaptor<Note> noteCaptor;
// if created in the test method
ArgumentCaptor<Note> noteCaptor = ArgumentCaptor.forClass(Note.class);
// ...
verify(noteRepository,times(1)).save(noteCaptor.capture());
assertThat(noteCaptor.getValue().geMyUser()).isEqualTo(testing);
assertThat(noteCaptor.getValue().geTime()).isCloseTo(someDate);
注意我在 phone
我刚开始使用 Mockito,我遇到了一个测试失败的问题,但实际代码在实时环境中运行正常。正在测试的控制器是:
@Controller
@RequestMapping("/notes")
public class NotesController {
private NoteRepository noteRepository;
private MyUserRepository userRepository;
@RequestMapping(value = "/add", method = POST)
public String postNote(@Valid Note note, BindingResult errors, Principal principal){
String username = principal.getName();
MyUser user = userRepository.findUserByUsername(username);
note.setMyUser(user);
note.setTime(new Date());
noteRepository.save(note);
return "redirect:/notes"; }
}
测试在这里:
@Test
public void testShouldAddValidNote() throws Exception {
MyUser testing = new MyUser();
Note note = new Note();
NoteRepository noteRepository = mock(NoteRepository.class);
when(noteRepository.save(note)).thenReturn(note);
MyUserRepository userRepository = mock(MyUserRepository.class);
when(userRepository.findUserByUsername("testing")).thenReturn(testing);
Principal mockPrincipal = mock(Principal.class);
when(mockPrincipal.getName()).thenReturn("testing");
NoteController controller = new NoteController(noteRepository);
controller.setMyUserRepository(userRepository);
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(post("/notes/add")
.requestAttr("note", note)
.principal(mockPrincipal))
.andExpect(view().name("redirect:/notes"));
verify(noteRepository,times(1)).save(note);
verify(note,times(1)).setMyUser(testing);
verify(note,times(1)).setTime((Date)anyObject());
verify(userRepository,times(1)).findUserByUsername("testing");
verify(mockPrincipal,times(1)).getName();
}
第一个验证测试失败,并显示消息:
Argument(s) are different! Wanted:
noteRepository.save(projectName.Note@5ae9);
Actual invocation has different arguments:
noteRepository.save(projectName.Note@c079ae45
显然传入方法的 Note 对象已经改变,但我认为使用 .requestAttr("note", note) 会传入引用,因此相同的对象应该在方法中(并且后来回来了)。就像我说的,它在实时网络容器中完美运行,请问我在 Mockito 测试中出了什么问题?
这只是一个大胆的猜测,此代码面临的问题是否来自 MockMvc
/ MockMvcRequestBuilders
,其中 Note
在请求配置和实际请求之间以某种方式序列化/反序列化?
请注意 note
是一个真实对象,因此调用 verify(note)....
将不起作用。
无论如何,我建议在这种情况下结合使用 mockito captor 和 AssertJ:
// if field instantiation if using the mockito runner / rule or MockitoAnnotations.initMocks(this)
@Captor ArgumentCaptor<Note> noteCaptor;
// if created in the test method
ArgumentCaptor<Note> noteCaptor = ArgumentCaptor.forClass(Note.class);
// ...
verify(noteRepository,times(1)).save(noteCaptor.capture());
assertThat(noteCaptor.getValue().geMyUser()).isEqualTo(testing);
assertThat(noteCaptor.getValue().geTime()).isCloseTo(someDate);
注意我在 phone