Spy in Mockito

JavaJavaBeginner
Practice Now

Introduction

Mockito is a Java framework used for mocking and unit testing Java applications. In this lab, we will learn about spies in Mockito. A Spy is like a partial mock, which will track the interactions with the object like a mock. Additionally, it allows us to call all the normal methods of the object. We will use the Mockito.spy() method and annotations to create spies and demonstrate how to stub a Spy.

Create a Java Class

Create a new Java file with the name MockitoSpyDemo.java in the ~/project directory. Copy the code below into the file.

import org.junit.Test;
import org.junit.Before;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import static org.junit.Assert.*;

public class MockitoSpyDemo {

}

Using Mockito.spy() Method

Use the Mockito.spy() method to create a spy for an ArrayList. In the @Test method, add elements to the spy ArrayList and verify that the interactions took place using the Mockito.verify() method.

@Test
public void testSpyWithMockitoSpyMethod() {
    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());
}

Run the code with the following command in the terminal:

javac MockitoSpyDemo.java && java MockitoSpyDemo

Using @Spy Annotation

Use the @Spy annotation to create a spy object for an ArrayList. The MockitoAnnotations.initMocks(this) method is used in the @Before method to initialize the spy object. In the @Test method, add elements to the spy ArrayList and verify that the interactions took place using the Mockito.verify() method.

//Using @Spy Annotation
@Spy
ArrayList<Integer> spyArrList = new ArrayList<>();

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

@Test
public void testSpyWithAtSpyAnnotation() {
    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());
}

Run the code with the following command in the terminal:

javac MockitoSpyDemo.java && java MockitoSpyDemo

Using @RunWith(MockitoJUnitRunner.class)

Create a new test method with the @RunWith(MockitoJUnitRunner.class) annotation. Use the @Spy annotation to create a spy object for an ArrayList. In the test method, add elements to the spy ArrayList and verify that the interactions took place using the Mockito.verify() method.

@RunWith(MockitoJUnitRunner.class)
public class MockitoSpyDemo {

    //Using @Spy Annotation
    @Spy
    ArrayList<Integer> spyArrList = new ArrayList<>();

    @Test
    public void testSpyWithRunWithAnnotation() {
        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());
    }
}

Run the code with the following command in the terminal:

javac MockitoSpyDemo.java && java MockitoSpyDemo

Stubbing a Spy

Create a new test method to demonstrate how to stub a spy. Use the Mockito.spy() method to create a spy object for an ArrayList. Add an element to the spy object and verify the normal behavior of the contains() method. Then, write a stub to override the default behavior of the contains() method to always return false for the value 5, and verify the stubbed behavior.

@Test
public void testStubbingSpy() {
    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
}

Run the code with the following command in the terminal:

javac MockitoSpyDemo.java && java MockitoSpyDemo

Mock vs Spy in Mockito

Create a new test method to demonstrate the difference between a mock and a spy object. Create a mock and a spy object for an ArrayList. Add an element to both objects and verify the interactions took place. Verify the size of the lists. The size of the mock list should be zero since the add method didn't do anything, while the spy should have a size of one, indicating that the add method worked.

@Test
public void testMockVsSpy() {
    //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());
}

Run the code with the following command in the terminal:

javac MockitoSpyDemo.java && java MockitoSpyDemo

Mockito NotAMockException

Create a new test method to demonstrate the NotAMockException. Use an ArrayList and try to use the verify method on it. The NotAMockException is thrown since the ArrayList is not a mock, and we cannot use the verify method on it. The exception is also accompanied by suggestions on how to use the method properly.

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

Run the code with the following command in the terminal:

javac MockitoSpyDemo.java && java MockitoSpyDemo

Summary

In this lab, we learned about Spy objects of the Mockito framework, which are like partial mocks with full object functionality. We used the Mockito.spy() method and annotations to create spies, stubbed a Spy to override the default behavior of methods, and demonstrated the difference between a mock and a spy object. We also learned about the NotAMockException, which is thrown if Mockito methods are not used properly.

Other Java Tutorials you may like