1

我想使用 mockito 间谍。

当我通过以下两种方式设置返回值时:

when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate));

doReturn(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user, fakeNowDate)).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

我看到正在热切地评估返回值

表示何时执行此“设置”行。

我怎样才能强制间谍只在需要时评估返回值?

表示何时满足“何时”条件。

更新

感谢@RobbyCornelissen,我尝试了以下代码:

    when(imagesSorterSpy.sortImages(imagesAsInsertionOrder, user)).thenAnswer(new Answer() {
        public Object answer(InvocationOnMock invocation) {
            Object[] args = invocation.getArguments();
            ImagesSorter mock = (ImagesSorter)invocation.getMock();
            return mock.sortImages((List<Image>)args[0], (UserInfo)args[1], fakeNowDate);
        }
    });

但这没有帮助:

1) "when" 表达式被立即调用。(不想要)

2)最终没有调用回调。

4

2 回答 2

2

首先让我警告你部分模拟,因为那是代码实际在做的事情,这是错误的设计明智的。使用策略模式来组合测试对象的行为可能更相关。Mockito 团队(包括我)强烈建议尽可能远离部分模拟。

编辑:我不知道代码,也不确切知道正在测试哪个组件,但据我所知,有一种负责对图像进行排序的类型,我们称之为ImagesSorter

  1. 所以第一种情况ImagesSorter是测试对象的依赖关系,所以在这种情况下,只需将mock存根就ImagesSorter可以了。

  2. 但是,如果它ImagesSorter本身正在测试中,并且对此类的特殊方法进行存根称为部分模拟,那是完全错误的。它在测试中暴露了生产代码的内部。所以有几种解决方案。

    1. 正如答案中显示的代码片段显示的那样fakeDate,解决方案之一是不使用类似的东西new Date()并编写一个简单的类TimeSource,其唯一职责是提供日期。并且在测试中,这个 bwhaviorTimeSOurce可以被覆盖。

      一个更简单的解决方案是使用 JodaTime,因为它提供了内置的功能。

    2. 如果测试的范围超出了更改日期,那么可能ImagesSorter需要一种方法来配置其他对象。可以从 guava 的缓存生成器中找到有关如何执行此操作的灵感。如果配置很简单,那么一个简单的构造函数就可以做到。

      这可能看起来像:

      class ImagesSorter { 
          ImagesSorterAlso algo;
          ImagesSorter(ImagesSorterAlgo algo) { this.algo = algo; }
          Iterable sortImages(...) {
             algo.sort(...);
          }
      }
      
      interface ImagesSorterAlgo {
          Iterable sort(...);
      }
      

现在关于您的问题:

1) "when" 表达式被立即调用。(不想要)

预计imagesSorterSpy是间谍,因此默认情况下它会调用真实代码。相反,您应该使用备用 API,与 @RobbyCornelissen 显示的相同。IE

doAnswer(sortWithFakeDate()).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

// with BDD aliases (BDDMockito) which I personnaly finds better
willAnswer(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
will(sortWithFakeDate()).given(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);

sortWithFakeDate()将是一个返回答案的静态工厂方法,因此代码读起来很好,并且可能在其他地方重用。

2)最终没有调用回调。

这个问题很可能是由于不相等的论点。您可能需要检查equals方法。any()或者使用匹配器放松存根。

于 2014-10-01T10:58:02.370 回答
1

我不知道您正在使用的参数和类的类型,所以我无法提供完整的示例,但您可以使用带有Answer<T>接口的回调进行存根:

Mockito.doAnswer(new Answer() {
    Object answer(InvocationOnMock invocation) {
         ImagesSorter mock = (ImagesSorter) invocation.getMock();
         Object[] args = invocation.getArguments();

         return mock.sortImages((List<Image>) args[0], (UserInfo) args[1],
                 fakeNowDate);
    }
}).when(imagesSorterSpy).sortImages(imagesAsInsertionOrder, user);
于 2014-10-01T10:10:02.453 回答