【问题标题】:Mocked repository does not trigger as expected模拟存储库未按预期触发
【发布时间】:2015-06-12 10:46:28
【问题描述】:

我有一个使用 Mockito 和 MockMvc 的控制器单元测试。

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

这是模拟代码:

    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);

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

不幸的是,存储库总是返回 null,因此我的代码稍后在尝试从 null 返回新创建的 Route 时失败。

模拟已正确注入并可以为例如字符串比较,或者如果我只检查函数是否被调用,我就是无法让它在对象上触发。

同样的问题发生在

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

它不会触发。

问题是: 1.) 为什么模拟没有触发?我想它不会检查对象中的值是否相等,而是检查对象标识符,因为对象在两者之间是序列化和反序列化的,所以它们是不一样的。

2.) 我怎样才能得到一个通用的模拟?例如每当调用 repository.save() 时,无论参数如何,它总是应该执行特定的方式,例如而不是

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

我想要

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

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

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

这里是Controller头,对象反序列化完美,值1:1相同

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

感谢您的帮助。

【问题讨论】:

标签: spring unit-testing mocking mockito mockmvc


【解决方案1】:

1.) 为什么模拟没有触发?我想它不检查对象中的值是否相等,而是检查对象标识符,它们不一样......

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

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

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

2.) 我怎样才能得到一个通用的模拟?例如每当调用 repository.save() 时,无论参数如何,它总是应该执行特定的方式

使用 Matchers,这非常简单:

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-04
      相关资源
      最近更新 更多