模拟框架中的模拟与间谍活动
Posted
技术标签:
【中文标题】模拟框架中的模拟与间谍活动【英文标题】:Mocking vs. Spying in mocking frameworks 【发布时间】:2012-10-01 09:51:06 【问题描述】:在模拟框架中,您可以模拟一个对象或窥探它。两者有什么区别,我什么时候应该/应该使用其中一个?
以 Mockito 为例,我看到使用 spies 和 mocks 可以做类似的事情,但我不确定两者之间的区别。
【问题讨论】:
martinfowler.com/bliki/TestDouble.html ***.com/questions/28295625/mockito-spy-vs-mock的可能重复 @Abhinav 这个问题比那个问题早。 【参考方案1】:基于 Martin Fowler 的 Mocks Aren't Stubs:
Dummy 对象被传递但从未实际使用过。通常它们只是用来填充参数列表。
Fake 对象实际上有工作实现,但通常采取一些捷径,这使得它们不适合生产(内存数据库就是一个很好的例子)。
存根为测试期间拨打的电话提供预设答案,通常根本不响应任何超出测试程序的内容。
Spies 是存根,它还根据调用方式记录一些信息。其中一种形式可能是电子邮件服务,它记录发送了多少消息。
Mocks 就是我们在此讨论的内容:预编程了期望的对象,这些期望形成了它们期望接收的调用的规范。
【讨论】:
【参考方案2】:我将尝试在这里用一个例子来解释:
// Difference between mocking, stubbing and spying
@Test
public void differenceBetweenMockingSpyingAndStubbing()
List list = new ArrayList();
list.add("abc");
assertEquals(1, list.size());
List mockedList = spy(list);
when(mockedList.size()).thenReturn(10);
assertEquals(10, mockedList.size());
这里,我们有初始的真实对象list
,我们在其中添加了一个元素并且预期大小为一。
我们窥探真实的对象意味着我们可以指示哪个方法被存根。所以我们声明我们在 spy object 上存根方法 - size()
,无论实际大小是多少,它都会返回 10。
简而言之,您将spy 真实对象和存根 一些方法。
【讨论】:
【参考方案3】:Mockito 警告说,部分模拟不是一个好的做法,您应该修改您的面向对象架构。 Spy(或部分模拟)建议用于测试遗留代码。
【讨论】:
【参考方案4】:在 Mockito 中,如果您将任何对象分配给 Mock Object 的实例变量,则不会影响 Mock Object。
但是在 Spy 的情况下,如果您将任何对象分配给 Spy Object 的实例变量,那么确实会影响 Spy Object,因为 Spy 的行为类似于实时对象修改。
供参考的例子有
@RunWith(MockitoJUnitRunner.class)
public class MockSpyExampleTest
@Mock
private List<String> mockList;
@Spy
private List<String> spyList = new ArrayList();
@Test
public void testMockList()
//by default, calling the methods of mock object will do nothing
mockList.add("test");
assertNull(mockList.get(0));
@Test
public void testSpyList()
//spy object will call the real method when not stub
spyList.add("test");
assertEquals("test", spyList.get(0));
【讨论】:
【参考方案5】:参考:http://javapointers.com/tutorial/difference-between-spy-and-mock-in-mockito/
当使用模拟对象时,方法在非存根时的默认行为是什么都不做。简单的意思是,如果它是一个 void 方法,那么当你调用该方法时它什么也不做,或者如果它是一个有返回值的方法,那么它可能返回 null、空或默认值。
虽然在 spy 对象中,当然,因为它是一个真实的方法,当你不存根该方法时,它会调用真实的方法行为。如果你想改变和模拟方法,那么你需要存根它。
【讨论】:
【参考方案6】:间谍有两个定义。一个是调用真实方法的地方,另一个是不调用任何功能并且只返回 null 或 null 等效值的地方,但是调用了方法,并且记录了它们的状态,通常就像方法 x 被调用了 y 次。
【讨论】:
【参考方案7】:模拟对象完全替换模拟类,返回记录或默认值。您可以“凭空”创建模拟。这是单元测试期间最常用的。
进行间谍活动时,您会获取现有对象并仅“替换”某些方法。当您有一个庞大的类并且只想模拟某些方法(部分模拟)时,这很有用。让我引用Mockito documentation:
您可以创建真实对象的间谍。当您使用 spy 时,会调用 真正的 方法(除非方法被存根)。
应该小心偶尔使用真正的间谍,例如在处理遗留代码时。
如有疑问,请使用模拟。
【讨论】:
谢谢!这使它更加清晰。所以模拟永远不会委托给被模拟的实际对象永远,但间谍会。 模拟没有“实际对象”——模拟是从头开始创建的。 任何解释为什么 Mockito 一直警告不要使用间谍?我看到他们说喜欢模拟,但我不清楚原因。 我不确定,但可能是因为它们是“Mockito”而不是“Spyito”:D 我的猜测是他们更喜欢模拟而不是间谍,因为你想在单元测试时尽可能地限制被测代码。通过使用 spy,您允许一些真正的实现代码运行,允许该依赖类的代码包含在您的测试中。以上是关于模拟框架中的模拟与间谍活动的主要内容,如果未能解决你的问题,请参考以下文章