模拟存储库未按预期触发

Mocked repository does not trigger as expected

我使用 Mockito 和 MockMvc 进行了控制器单元测试。

在 POST 请求后,POSTed object 被正确解析,但我的存储库模拟没有被触发。

这是模拟代码:

    Date mydate = new Date();
    Notification not = new Notification();
    not.setId(-1L);
    not.setUserid("BaBlubb");
    not.setTimestamp(mydate);
    not.setContent("MyContent");

    Notification not2 = new Notification();
    not2.setId(1L);
    not2.setUserid("BaBlubb");
    not2.setTimestamp(mydate);
    not2.setContent("MyContent");

    when(notificationRepository.save(not)).thenReturn(not2);

所以这真的应该模拟 object 的保存(设置 ID 并从中生成路由)。

不幸的是,存储库始终 return 为 null,因此我的代码后来在尝试 return 从 null 中创建新路由时失败。

mocks 被正确注入并且可以工作,例如。字符串比较或者如果我只检查函数是否被调用,我就是无法让它在 Objects.

上触发

同样的问题发生在

        verify(notificationRepository, times(1)).save(not);

不触发。

问题是: 1.) 为什么模拟不触发?我想它不会检查 object 中的值是否相等,但会检查 object 标识符,因为 object 是序列化的,而 de-serialized 是不一样的。

2.) 如何获得通用模拟?例如每当 repository.save() 被调用时,无论参数如何,它总是应该执行特定的方式,例如而不是

when(notificationRepository.save(not)).thenReturn(not2);

我想要

when(notificationRepository.save()).thenReturn(not2);

P.S。如果出于某种原因您需要其余代码,这里是提交的部分,object 是通知的 json 表示(使用 jackson)

 mockMvc.perform(post("/api/notification").content(object)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON));

这里是控制器 header,Object 完美 de-serialized,值 1:1 相同

 @RequestMapping(method=RequestMethod.POST)
    public ResponseEntity<?> postNotification(@RequestBody Notification n) {
        logger.debug("Saving userid "+n.getId());

感谢您的帮助。

1.) Why does the mock not trigger? I suppose it does not check for value equality in the object, but for object identifiers, which are not the same...

默认情况下,Mockito 委托给对象的 equals 方法。如果您没有覆盖它,那么默认情况下它会检查引用。下面两行是等价的:

when(notificationRepository.save(not)).thenReturn(not2);
when(notificationRepository.save(not)).thenReturn(eq(not2)); // uses eq explicitly

如果具有相同字段的所有通知对象都相同,那么覆盖 equalshashCode 将使您到达需要去的地方。但是请注意,这可能会对 Set 和 Map 行为产生意想不到的副作用,尤其是当您的 Notification 对象在保存之前没有 ID 时。

2.) How can I get a generic mock? e.g. whenever repository.save() is called, no matter the parameter, it always should perform a specific way

使用 Matchers,这非常简单:

when(notificationRepository.save(not)).thenReturn(any(Notification.class));

尽管 Matchers 非常强大,但请注意:它们 have some tricky rules 与它们的使用相关联。

对于 (1),如 Jeff 所述,您可能需要使用 eq() 而不是直接引用 not1
对于 (2) 您可以使用 Mockito.any()
例如when(notificationRepository.save(any(Notification.class))).thenReturn(not2);
这将在模拟对象 notificationRepository 上创建存根,对于 Notification 类型的任何参数,它总是 return not2。如果 save() 方法接受 Object 那么你可以写 when(notificationRepository.save(any(Object.class))).thenReturn(not2); 这将 return not2 用于 Object

类型的任何参数