【问题标题】:Mocking vs. Spying in mocking frameworks模拟框架中的模拟与间谍活动
【发布时间】:2012-10-01 09:51:06
【问题描述】:

在模拟框架中,您可以模拟一个对象或窥探它。两者有什么区别,我什么时候应该/应该使用其中一个?

Mockito 为例,我看到使用 spiesmocks 可以做类似的事情,但我不确定两者之间的区别。

【问题讨论】:

标签: unit-testing mocking tdd


【解决方案1】:

基于 Martin FowlerMocks 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,您允许一些真正的实现代码运行,允许该依赖类的代码包含在您的测试中。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2020-10-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多