Mockito 的间谍

原文:https://www.studytonight.com/java-examples/spy-in-mockito

Mockito 是一个 Java 框架,用于模拟单元测试 Java 应用。在内部,这个框架使用反射 API。Mockito 通过创建模拟对象和避免外部依赖来简化测试过程。它与其他测试框架一起使用,如 JUnitTestNG

在本教程中,我们将了解 Mockito 的间谍。

莫基托间谍

间谍就像一个局部模拟,它会像模拟一样跟踪与对象的交互。此外,它允许我们调用对象的所有正常方法。每当我们调用间谍对象的一个方法时,真正的方法就会被调用(除非它被存根化)。

使用 Mockito.spy()方法创建间谍

在下面的代码中,我们为ArrayList创建了一个间谍。Mockito.spy()方法用于此目的。验证()方法用于验证交互是否发生。当对间谍调用 add()方法时,将调用实际的方法,并将元素添加到列表中。我们可以通过查看列表的大小来验证它。

public class MockitoSpyDemo
{
    @Test
    public void test()
    {
        ArrayList<Integer> arrList = new ArrayList<>();
        ArrayList<Integer> spyArrList = Mockito.spy(arrList);

        //Adding Elements
        spyArrList.add(5);
        spyArrList.add(10);
        spyArrList.add(15);

        //Verifying interactions
        Mockito.verify(spyArrList).add(5);
        Mockito.verify(spyArrList).add(10);
        Mockito.verify(spyArrList).add(15);

        //Verifying that elements were actually added to the list
        assertEquals(3, spyArrList.size());
    }
}

使用@间谍注释创建间谍

我们也可以使用@Spy 注释创建一个间谍对象。要启用 Mockito 注释,我们可以使用mockitonations . init mocks(this)方法。或者我们可以使用内置的 runner@ RunWith(mockitojunitrunner . class)。两者的示例如下所示。

使用模拟注释

public class MockitoSpyDemo
{
    //Using @Spy Annotation
    @Spy
    ArrayList<Integer> spyArrList = new ArrayList<>();

    @Before
    public void init()
    {
        MockitoAnnotations.initMocks(this); 
    }

    @Test
    public void test()
    {
        spyArrList.add(5);
        spyArrList.add(10);
        spyArrList.add(15);

        Mockito.verify(spyArrList).add(5);
        Mockito.verify(spyArrList).add(10);
        Mockito.verify(spyArrList).add(15);

        assertEquals(3, spyArrList.size());
    }
}

使用@ RunWith(mockitojunitrunner . class)

@RunWith(MockitoJUnitRunner.class)
public class MockitoSpyDemo
{
    //Using @Spy Annotation
    @Spy
    ArrayList<Integer> spyArrList = new ArrayList<>();

    @Test
    public void test()
    {
        spyArrList.add(5);
        spyArrList.add(10);
        spyArrList.add(15);

        Mockito.verify(spyArrList).add(5);
        Mockito.verify(spyArrList).add(10);
        Mockito.verify(spyArrList).add(15);

        assertEquals(3, spyArrList.size());
    }
}

干掉一名间谍

我们可以截取一个间谍来覆盖一个方法的正常行为。让我们覆盖 ArrayLists 的 contains()方法的默认行为。让我们让这个方法总是为值 5 返回 false。

public class MockitoSpyDemo
{
    @Test
    public void test()
    {
        ArrayList<Integer> spyArrList = Mockito.spy(new ArrayList<>());
        spyArrList.add(5);
        Mockito.verify(spyArrList).add(5);
        assertEquals(true, spyArrList.contains(5));//Default normal behavior

        Mockito.doReturn(false).when(spyArrList).contains(5);
        assertEquals(false, spyArrList.contains(5));//Stubbed Behavior
    }
}

让我们覆盖ArrayList的 size()方法。它应该总是返回 5 作为列表大小。

public class MockitoSpyDemo
{
    @Test
    public void test()
    {
        ArrayList<Integer> spyArrList = Mockito.spy(new ArrayList<>());        
        spyArrList.add(5);
        Mockito.verify(spyArrList).add(5);
        assertEquals(1, spyArrList.size());//Default Normal Behavior

        Mockito.doReturn(5).when(spyArrList).size();
        assertEquals(5, spyArrList.size());//Stubbed Behavior
    }
}

Mockito 的模拟 vs 间谍

间谍被称为部分嘲讽。模拟是从一个类型的类中创建的,而间谍是从类的实际实例中创建的。在模拟的情况下,类的所有正常方法都不会被执行。另一方面,间谍会使用原始行为的方法。方法执行的结果也反映在间谍对象上。

例如,在下面的代码中,我们有一个模拟和一个间谍。两个对象都验证了交互。但是当 add()方法被调用时,一个元素只被添加到间谍列表中。模拟列表的大小为零,表明 add()方法没有做任何事情。

public class MockitoSpyDemo
{
    @Test
    public void test()
    {
        //Creating a spy and a mock
        ArrayList<Integer> spyArrList = Mockito.spy(new ArrayList<Integer>());
        ArrayList<Integer> mockArrList = Mockito.mock(ArrayList.class);

        //Adding an element to spy and mock
        spyArrList.add(5);
        mockArrList.add(5);

        //Verifying the interaction
        Mockito.verify(spyArrList).add(5);
        Mockito.verify(mockArrList).add(5);

        //verifying the size of the spy and the mock
        assertEquals(1, spyArrList.size());
        assertEquals(0, mockArrList.size());
    }
}

莫基托注意到异常

使用 Mockito 时,经常会遇到 NotAMockException。当我们试图在其他对象上使用模拟特定的方法时,会引发此异常。例如,在下面的代码中,我们创建了一个ArrayList,但它不是模拟的。当我们对其使用 verify()方法时,会引发 NotAMockException。正如异常的名称所示,ArrayList不是模拟的,我们不能对它使用 verify()方法。例外情况还附带了一些如何使用该方法的建议。

public class MockitoSpyDemo
{
    @Test
    public void test()
    {
        ArrayList<Integer> arrList = new ArrayList<>();
        arrList.add(5);
        Mockito.verify(arrList).add(5);//NotAMockException
    }
}

org . mock ITO . exceptions . misusing . nota mock exception: 传递给 verify()的参数属于 ArrayList 类型,不是 mock! 确保括号放置正确! 参见正确验证示例: 验证(模拟)。some method(); 验证(模拟,次数(10))。some method(); 验证(模拟,至少测试())。some method(); 在 Demo.test(Demo.java:15)

摘要

Mockito 框架用于 Java 应用的单元测试。在本教程中,我们学习了 Mockito 框架的间谍对象。与模拟不同,间谍执行对象的真实方法,方法的结果也反映在对象中。我们还了解了 NotAMockException,如果 Mockito 方法使用不当,就会引发该异常。