Mockito doReturn()

Introduction

The doReturn() method in Mockito is used to stub a method call with a specific return value. It is particularly useful when you want to stub methods that cannot be stubbed with when(), such as void methods or when chaining method calls. This tutorial will demonstrate how to use the doReturn() method in Mockito to handle method stubbing.

Maven Dependencies

To use Mockito with JUnit 5, add the following dependencies to your pom.xml file:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>4.8.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

Example Scenario

We will create a LibraryService class that has a dependency on a BookRepository. Our goal is to test the LibraryService methods using the doReturn() method in Mockito to stub method calls with specific return values.

LibraryService and BookRepository Classes

First, create the Book class, the BookRepository interface, and the LibraryService class.

public class Book {
    private String title;
    private String author;

    // Constructor, getters, and setters
    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

public interface BookRepository {
    Book findBookByTitle(String title);
    void saveBook(Book book);
}

public class LibraryService {
    private final BookRepository bookRepository;

    public LibraryService(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    public Book getBookDetails(String title) {
        return bookRepository.findBookByTitle(title);
    }

    public void addBook(String title, String author) {
        Book book = new Book(title, author);
        bookRepository.saveBook(book);
    }
}

JUnit 5 Test Class with Mockito

Create a test class for LibraryService using JUnit 5 and Mockito.

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

@ExtendWith(MockitoExtension.class)
public class LibraryServiceTest {

    @Mock
    private BookRepository bookRepository;

    @InjectMocks
    private LibraryService libraryService;

    @Test
    public void testGetBookDetails() {
        // Given
        String title = "Mockito in Action";
        Book book = new Book(title, "Sanjay Kumar");
        doReturn(book).when(bookRepository).findBookByTitle(title);

        // When
        Book result = libraryService.getBookDetails(title);

        // Then
        assertNotNull(result);
        assertEquals(title, result.getTitle());
        assertEquals("Sanjay Kumar", result.getAuthor());
    }

    @Test
    public void testAddBook() {
        // Given
        String title = "Effective Java";
        String author = "Joshua Bloch";

        // When
        libraryService.addBook(title, author);

        // Then
        Book book = new Book(title, author);
        verify(bookRepository).saveBook(book);
    }
}

Explanation

  1. Creating Mocks with @Mock:

    • The @Mock annotation creates a mock instance of the BookRepository interface. This mock instance can be used to simulate the behavior of the BookRepository in a controlled way.
  2. Injecting Mocks with @InjectMocks:

    • The @InjectMocks annotation injects the mock BookRepository into the LibraryService instance to provide a controlled test environment. This allows the LibraryService methods to be tested in isolation from the actual BookRepository implementation.
  3. Stubbing Methods with doReturn():

    • The doReturn(book).when(bookRepository).findBookByTitle(title); method configures the mock BookRepository to return a specific Book object when the findBookByTitle method is called with the specified title. This allows the getBookDetails method of the LibraryService class to be tested with controlled behavior from the BookRepository.
  4. Verifying Interactions with verify():

    • The verify(bookRepository).saveBook(book); method checks if the saveBook method was called on the BookRepository with the expected Book object. This ensures that the addBook method of the LibraryService class interacts with the BookRepository correctly.

Additional Scenarios

Scenario: Stubbing Void Methods

In this scenario, we will demonstrate how to stub a void method using the doReturn() method.

@Test
public void testAddBookWithDoReturn() {
    // Given
    String title = "Clean Code";
    String author = "Robert C. Martin";
    Book book = new Book(title, author);
    doNothing().when(bookRepository).saveBook(book);

    // When
    libraryService.addBook(title, author);

    // Then
    verify(bookRepository).saveBook(book);
}

Explanation

  1. Stubbing Void Methods:
    • The doNothing().when(bookRepository).saveBook(book); method configures the mock BookRepository to do nothing when the saveBook method is called with the specified Book object. This allows the addBook method of the LibraryService class to be tested without actual interaction with the BookRepository.

Scenario: Stubbing Methods with Chained Calls

In this scenario, we will demonstrate how to stub methods with chained calls using the doReturn() method.

@Test
public void testGetBookDetailsWithChainedCalls() {
    // Given
    String title = "Refactoring";
    Book book = new Book(title, "Martin Fowler");
    doReturn(book).when(bookRepository).findBookByTitle(title);

    // When
    Book result = libraryService.getBookDetails(title);

    // Then
    assertNotNull(result);
    assertEquals(title, result.getTitle());
    assertEquals("Martin Fowler", result.getAuthor());
}

Explanation

  1. Stubbing Methods with Chained Calls:
    • The doReturn(book).when(bookRepository).findBookByTitle(title); method configures the mock BookRepository to return a specific Book object when the findBookByTitle method is called with the specified title. This allows the getBookDetails method of the LibraryService class to be tested with controlled behavior from the BookRepository.

Conclusion

The doReturn() method in Mockito simplifies the stubbing of method calls on mock objects for unit testing. By using doReturn(), you can handle method stubbing flexibly, ensuring that the code under test interacts with its dependencies as expected. This step-by-step guide demonstrated how to effectively use the doReturn() method in your unit tests, covering different scenarios to ensure comprehensive testing of the LibraryService class.

Related Mockito Methods

Mockito mock()
Mockito spy()
Mockito when()
Mockito thenThrow()
Mockito verify()
Mockito times()
Mockito never()
Mockito any()
Mockito eq()
Mockito inOrder()
Mockito doReturn()
Mockito doThrow()
Mockito doAnswer()
Mockito timeout()
Mockito ArgumentMatchers

Comments