莫基托 - @Spy vs @Mock

2022-08-31 07:27:04

Mockito - 我知道间谍在对象上调用真实方法,而模拟在双对象上调用方法。此外,除非有代码异味,否则应避免间谍。但是,间谍是如何工作的,我什么时候应该实际使用它们?它们与模拟有何不同?


答案 1

从技术上讲,“模拟”和“间谍”都是一种特殊的“测试替身”。

不幸的是,Mockito使这种区别变得奇怪。

mockito 中的 mock 是其他 mocking 框架中的普通 mock(允许您存根调用;即,从方法调用中返回特定值)。

mockito中的间谍是其他模拟框架中的部分模拟(部分对象将被模拟,部分将使用真实方法调用)。


答案 2

两者都可用于模拟方法或字段。不同之处在于,在模拟中,您正在创建一个完整的模拟或假对象,而在间谍中,有真实对象,您只是监视或存根它的特定方法。

当然,在间谍对象中,由于它是一个真正的方法,因此当您不存根该方法时,它将调用真正的方法行为。如果要更改和模拟该方法,则需要对其进行存根。

请考虑以下示例作为比较。

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
 
import java.util.ArrayList;
import java.util.List;
 
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
 
@RunWith(MockitoJUnitRunner.class)
public class MockSpy {
 
    @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");

        Mockito.verify(mockList).add("test");
        assertEquals(0, mockList.size());
        assertNull(mockList.get(0));
    }
 
    @Test
    public void testSpyList() {
        //spy object will call the real method when not stub
        spyList.add("test");

        Mockito.verify(spyList).add("test");
        assertEquals(1, spyList.size());
        assertEquals("test", spyList.get(0));
    }
 
    @Test
    public void testMockWithStub() {
        //try stubbing a method
        String expected = "Mock 100";
        when(mockList.get(100)).thenReturn(expected);
 
        assertEquals(expected, mockList.get(100));
    }
 
    @Test
    public void testSpyWithStub() {
        //stubbing a spy method will result the same as the mock object
        String expected = "Spy 100";
        //take note of using doReturn instead of when
        doReturn(expected).when(spyList).get(100);
 
        assertEquals(expected, spyList.get(100));
    }
}

当你使用模拟或间谍时?如果您想安全并避免调用外部服务,并且只想测试单元内部的逻辑,请使用mock。如果你想调用外部服务并执行真正依赖关系的调用,或者简单地说,你想按原样运行程序,只是存根特定的方法,那么使用spy。这就是间谍和嘲笑之间的区别。


推荐