使用Mockito时嘲讽和间谍有什么区别?

问题

什么是使用Mockito间谍的用例?

在我看来,使用callRealMethod可以使用mock处理每个间谍用例。

我可以看到的一个区别是,如果你希望大多数方法调用都是真实的,它会节省一些代码行来使用模拟与间谍。这是它还是我错过了更大的图景?


#1 热门回答(80 赞)

答案是在the documentation

真正的部分嘲笑(自1.8.0开始)最后,在邮件列表上进行了许多内部辩论和讨论之后,Mockito增加了部分模拟支持。以前我们认为部分模拟是代码味道。但是,我们发现了一个合理的部分模拟用例 - 更多阅读:这里发布之前1.8 spy()并没有产生真正的部分模拟,这让一些用户感到困惑。

callRealMethod()是在spy()之后推出的,但当然留下间谍(),以确保向后兼容。

否则,你是对的:间谍的所有方法都是真实的,除非被抄袭。除非调用callRealMethod(),否则模拟的所有方法都是存根的。一般来说,我更喜欢使用callRealMethod(),因为它不会强迫我使用488916149idiom而不是传统的when().thenXxx()


#2 热门回答(52 赞)

间谍与模拟之间的区别
当Mockito创建一个模拟时 - 它是从类的类中完成的,而不是从实际的实例中创建的。模拟只是创建了一个类的裸骨shell实例,完全用于跟踪与它的交互。另一方面,间谍将包装现有实例。它仍将以与普通实例相同的方式运行 - 唯一的区别是它还将被检测以跟踪与它的所有交互。

在下面的示例中 - 我们创建了一个ArrayList类的模拟:

@Test
public void whenCreateMock_thenCreated() {
    List mockedList = Mockito.mock(ArrayList.class);

    mockedList.add("one");
    Mockito.verify(mockedList).add("one");

    assertEquals(0, mockedList.size());
}

正如你所看到的 - 在模拟列表中添加元素实际上并没有添加任何内容 - 它只调用方法而没有其他副作用。另一方面,间谍的行为会有所不同 - 它实际上会调用add方法的实际实现并将元素添加到基础列表中:

@Test
public void whenCreateSpy_thenCreate() {
    List spyList = Mockito.spy(new ArrayList());
    spyList.add("one");
    Mockito.verify(spyList).add("one");

    assertEquals(1, spyList.size());
}

在这里我们可以肯定地说,对象的真正内部方法被调用,因为当你调用size()方法时,你得到的大小为1,但是这个size()方法没有被模拟!**那么1来自哪里?**调用内部实际size()方法,因为size()没有被模拟(或存根),因此我们可以说该条目已添加到真实对象中。

资料来源:http://www.baeldung.com/mockito-spy自我说明。


#3 热门回答(29 赞)

如果有一个包含8个方法的对象,并且你有一个测试,你想要调用7个实际方法并存根一个方法,那么你有两个选项:

  • 使用模拟,你必须通过调用7 callRealMethod和stub一个方法来设置它
  • 使用间谍你必须通过一个方法来设置它

The official documentationondoCallRealMethod建议使用间谍进行部分嘲笑。

另请参阅javadoc spy(Object)以了解有关部分模拟的更多信息。 Mockito.spy()是一种创建部分模拟的推荐方法。原因是它保证对正确构造的对象调用实际方法,因为你负责构造传递给spy()方法的对象。