Mocking in Java with Mockito

Loading

Mockito is a popular mocking framework for Java that allows you to create and configure mock objects for unit testing. It simplifies the process of testing by allowing you to simulate the behavior of complex dependencies. Below is a comprehensive guide to using Mockito for mocking in Java.


Key Features of Mockito

  1. Mock Creation: Easily create mock objects for interfaces and classes.
  2. Stubbing: Define the behavior of mock objects.
  3. Verification: Verify interactions with mock objects.
  4. Annotations: Use annotations to simplify mock creation and injection.
  5. Argument Matchers: Use matchers to define flexible stubbing and verification.

Setting Up Mockito

1. Add Dependencies

Add the following dependencies to your pom.xml for a Maven project:

<dependencies>
    <!-- Mockito Core -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>4.5.1</version>
        <scope>test</scope>
    </dependency>

    <!-- JUnit (for testing) -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2. Import Mockito Classes

Import the necessary Mockito classes in your test class.

import static org.mockito.Mockito.*;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

Basic Usage of Mockito

1. Create a Mock Object

Use Mockito.mock() to create a mock object.

@Test
public void testMockCreation() {
    List<String> mockedList = mock(List.class);
    when(mockedList.get(0)).thenReturn("first");
    assertEquals("first", mockedList.get(0));
}

2. Stubbing

Define the behavior of mock objects using when().thenReturn().

@Test
public void testStubbing() {
    List<String> mockedList = mock(List.class);
    when(mockedList.get(0)).thenReturn("first");
    when(mockedList.get(1)).thenThrow(new RuntimeException("Exception"));

    assertEquals("first", mockedList.get(0));
    assertThrows(RuntimeException.class, () -> mockedList.get(1));
}

3. Verification

Verify interactions with mock objects using verify().

@Test
public void testVerification() {
    List<String> mockedList = mock(List.class);
    mockedList.add("one");
    mockedList.add("two");

    verify(mockedList).add("one");
    verify(mockedList, times(2)).add(anyString());
}

Advanced Usage of Mockito

1. Annotations

Use annotations to simplify mock creation and injection.

@ExtendWith(MockitoExtension.class)
public class ExampleTest {

    @Mock
    private List<String> mockedList;

    @InjectMocks
    private SomeService someService;

    @Test
    public void testAnnotations() {
        when(mockedList.get(0)).thenReturn("first");
        assertEquals("first", someService.getList().get(0));
    }
}

2. Argument Matchers

Use argument matchers for flexible stubbing and verification.

@Test
public void testArgumentMatchers() {
    List<String> mockedList = mock(List.class);
    when(mockedList.get(anyInt())).thenReturn("element");

    assertEquals("element", mockedList.get(0));
    assertEquals("element", mockedList.get(1));

    verify(mockedList, times(2)).get(anyInt());
}

3. Spying

Use spy() to create a partial mock that wraps a real object.

@Test
public void testSpying() {
    List<String> realList = new ArrayList<>();
    List<String> spyList = spy(realList);

    spyList.add("one");
    spyList.add("two");

    verify(spyList).add("one");
    verify(spyList).add("two");

    assertEquals(2, spyList.size());
}

4. Capturing Arguments

Use ArgumentCaptor to capture arguments for further assertions.

@Test
public void testArgumentCaptor() {
    List<String> mockedList = mock(List.class);
    mockedList.add("one");

    ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
    verify(mockedList).add(captor.capture());

    assertEquals("one", captor.getValue());
}

Best Practices

  1. Use Annotations: Simplify mock creation and injection with annotations.
  2. Keep Tests Simple: Focus on testing one behavior per test.
  3. Avoid Over-Mocking: Only mock necessary dependencies.
  4. Verify Interactions: Ensure that the expected interactions with mocks occur.
  5. Use Argument Matchers: Make stubbing and verification more flexible.

Resources


Leave a Reply

Your email address will not be published. Required fields are marked *