Mockito Stubbing Methods

Introduction

In this chapter, we will learn about stubbing methods with Mockito. Stubbing is a key concept in unit testing, allowing you to define the behavior of mock objects. This helps you isolate the code you are testing and control the responses of its dependencies.

What is Stubbing?

Stubbing is the process of specifying what mock objects should do when their methods are called. By defining the behavior of mock objects, you can control their interactions and ensure that your tests are reliable and predictable. Stubbing allows you to return specific values, throw exceptions, or execute custom logic when a method is called.

Stubbing Void Methods

Void methods do not return a value, but you can still control their behavior. You might want to stub void methods to do nothing, throw an exception, or perform some custom action.

Example: EmailService Class and EmailServiceTest Class

Class Under Test: EmailService

public class EmailService {
    public void sendEmail(String recipient, String message) {
        // Logic to send email
        System.out.println("Sending email to " + recipient + ": " + message);
    }
}

Test Class: EmailServiceTest

import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;

public class EmailServiceTest {

    @Test
    void testVoidMethod() {
        // Create a mock object of EmailService
        EmailService emailService = mock(EmailService.class);

        // Stub the void method to do nothing
        doNothing().when(emailService).sendEmail(anyString(), anyString());

        // Call the void method
        emailService.sendEmail("test@example.com", "Hello");

        // Verify that the void method was called
        verify(emailService).sendEmail("test@example.com", "Hello");
    }

    @Test
    void testVoidMethod_ThrowException() {
        // Create a mock object of EmailService
        EmailService emailService = mock(EmailService.class);

        // Stub the void method to throw an exception
        doThrow(new RuntimeException("Exception occurred")).when(emailService).sendEmail(anyString(), anyString());

        // Call the void method and handle the exception
        RuntimeException exception = assertThrows(RuntimeException.class, () -> {
            emailService.sendEmail("test@example.com", "Hello");
        });

        assertEquals("Exception occurred", exception.getMessage());
    }
}

Stubbing with Specific Arguments

You can stub methods to return specific values when called with particular arguments.

Example: Calculator Class and CalculatorTest Class

Class Under Test: Calculator

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

Test Class: CalculatorTest

import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CalculatorTest {

    @Test
    void testStubbingWithArguments() {
        // Create a mock object of Calculator
        Calculator calculator = mock(Calculator.class);

        // Stub the add method with specific arguments
        when(calculator.add(2, 3)).thenReturn(5);

        // Use the mock object
        int result = calculator.add(2, 3);

        // Assert the result
        assertEquals(5, result);

        // Verify the interaction
        verify(calculator).add(2, 3);
    }
}

Running the Tests using IntelliJ IDEA

Stubbing with Specific Arguments

Stubbing with Argument Matchers

Argument matchers allow you to stub methods with flexible arguments. This is useful when you want to specify behavior for a range of inputs.

Example: Calculator Class and CalculatorTest Class

Class Under Test: Calculator

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

Test Class: CalculatorTest

import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CalculatorTest {

    @Test
    void testStubbingWithArgumentMatchers() {
        // Create a mock object of Calculator
        Calculator calculator = mock(Calculator.class);

        // Stub the add method with argument matchers
        when(calculator.add(anyInt(), anyInt())).thenReturn(10);

        // Use the mock object
        int result = calculator.add(4, 6);

        // Assert the result
        assertEquals(10, result);

        // Verify the interaction
        verify(calculator).add(anyInt(), anyInt());
    }
}

Stubbing with Callbacks

You can use callbacks to stub methods with custom logic. This allows you to define dynamic behavior for mock objects.

Example: Calculator Class and CalculatorTest Class

Class Under Test: Calculator

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

Test Class: CalculatorTest

import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class CalculatorTest {

    @Test
    void testStubbingWithCallbacks() {
        // Create a mock object of Calculator
        Calculator calculator = mock(Calculator.class);

        // Stub the add method with a callback
        when(calculator.add(anyInt(), anyInt())).thenAnswer(new Answer<Integer>() {
            @Override
            public Integer answer(InvocationOnMock invocation) {
                int a = invocation.getArgument(0);
                int b = invocation.getArgument(1);
                return a + b;
            }
        });

        // Use the mock object
        int result = calculator.add(4, 6);

        // Assert the result
        assertEquals(10, result);

        // Verify the interaction
        verify(calculator).add(4, 6);
    }
}

Explanation

  1. Stubbing with a Callback:
    when(calculator.add(anyInt(), anyInt())).thenAnswer(new Answer<Integer>() {
        @Override
        public Integer answer(InvocationOnMock invocation) {
            int a = invocation.getArgument(0);
            int b = invocation.getArgument(1);
            return a + b;
        }
    });
    

    This line stubs the add method with a callback that adds the two arguments and returns the result.

Conclusion

Stubbing methods with Mockito is a powerful way to control the behavior of mock objects in your tests. By understanding how to stub void methods, methods with specific arguments, methods with argument matchers, and methods with callbacks, you can create more flexible and effective tests. This will help you ensure that your code behaves as expected under various conditions.

Leave a Comment

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

Scroll to Top