Mockito BDDMockito given()

Introduction

BDDMockito.given() is a method provided by Mockito to support the Behavior-Driven Development (BDD) style of writing tests. It is used to set up mock objects with predefined behaviors, making the tests more readable and expressive. This tutorial will demonstrate how to use BDDMockito.given() to stub methods in a BDD style.

Maven Dependencies

To use Mockito with JUnit 5 and enable BDDMockito syntax, 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 BDDMockito.given() to handle stubbing.

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 {
    void saveBook(Book book);
    Book findBookByTitle(String title);
    List<Book> findAllBooks();
}

public class LibraryService {
    private final BookRepository bookRepository;

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

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

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

    public List<Book> getAllBooks() {
        return bookRepository.findAllBooks();
    }
}

JUnit 5 Test Class with BDDMockito

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

import static org.mockito.BDDMockito.*;
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;

import java.util.Arrays;
import java.util.List;

@ExtendWith(MockitoExtension.class)
public class LibraryServiceTest {

    @Mock
    private BookRepository bookRepository;

    @InjectMocks
    private LibraryService libraryService;

    @Test
    public void testAddBook() {
        // Given
        String title = "Mockito in Action";
        String author = "Ramesh Fadatare";

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

        // Then
        then(bookRepository).should().saveBook(any(Book.class));
    }

    @Test
    public void testGetBookByTitle() {
        // Given
        String title = "Mockito in Action";
        Book book = new Book(title, "Ramesh Fadatare");
        given(bookRepository.findBookByTitle(title)).willReturn(book);

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

        // Then
        assertNotNull(result);
        assertEquals(title, result.getTitle());
        assertEquals("Ramesh Fadatare", result.getAuthor());
    }

    @Test
    public void testGetAllBooks() {
        // Given
        Book book1 = new Book("Mockito in Action", "Ramesh Fadatare");
        Book book2 = new Book("Effective Java", "Joshua Bloch");
        List<Book> books = Arrays.asList(book1, book2);
        given(bookRepository.findAllBooks()).willReturn(books);

        // When
        List<Book> result = libraryService.getAllBooks();

        // Then
        assertNotNull(result);
        assertEquals(2, result.size());
        assertEquals("Mockito in Action", result.get(0).getTitle());
        assertEquals("Effective Java", result.get(1).getTitle());
    }

    @Test
    public void testAddBookWithCustomMatcher() {
        // Given
        String title = "Mockito in Action";
        String author = "Ramesh Fadatare";

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

        // Then
        then(bookRepository).should().saveBook(argThat(book -> book.getTitle().equals("Mockito in Action") && book.getAuthor().equals("Ramesh Fadatare")));
    }
}

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. Using BDDMockito:

    • given(): The given(bookRepository.findBookByTitle(title)).willReturn(book); method configures the mock BookRepository to return a specific Book object when the findBookByTitle method is called with the specified title.
    • then(): The then(bookRepository).should().saveBook(any(Book.class)); method verifies that the saveBook method was called on the BookRepository with any Book object.
    • argThat(): The then(bookRepository).should().saveBook(argThat(book -> book.getTitle().equals("Mockito in Action") && book.getAuthor().equals("Ramesh Fadatare"))); method verifies that the saveBook method was called on the BookRepository with a Book object that matches the specified title and author.

Additional Scenarios

Scenario: Handling Exceptions with BDDMockito

In this scenario, we will demonstrate how to handle exceptions using BDDMockito.

@Test
public void testGetBookByTitleThrowsException() {
    // Given
    String title = "Nonexistent Book";
    given(bookRepository.findBookByTitle(title)).willThrow(new RuntimeException("Book not found"));

    // When & Then
    RuntimeException exception = assertThrows(RuntimeException.class, () -> {
        libraryService.getBookByTitle(title);
    });
    assertEquals("Book not found", exception.getMessage());
}

Explanation

  1. Handling Exceptions with BDDMockito:
    • The given(bookRepository.findBookByTitle(title)).willThrow(new RuntimeException("Book not found")); method configures the mock BookRepository to throw a RuntimeException when the findBookByTitle method is called with the specified title. This allows the getBookByTitle method of the LibraryService class to be tested with controlled exception handling behavior.

Scenario: Verifying No Interactions

In this scenario, we will demonstrate how to verify that no interactions occurred with the mock object using BDDMockito.

@Test
public void testNoInteractionsWithBookRepository() {
    // Given
    // No interactions expected

    // When
    // No method calls

    // Then
    then(bookRepository).shouldHaveNoInteractions();
}

Explanation

  1. Verifying No Interactions:
    • The then(bookRepository).shouldHaveNoInteractions(); method verifies that no interactions occurred with the BookRepository mock object. This ensures that the BookRepository was not used during the test.

Conclusion

Using BDDMockito.given() in Mockito allows you to write more readable and expressive tests that follow the Behavior-Driven Development (BDD) style. By using given() for stubbing methods, you can handle various scenarios and control the behavior of mock objects. This step-by-step guide demonstrated how to effectively use BDDMockito.given() in your unit tests, covering different scenarios to ensure comprehensive testing of the LibraryService class.

Related Mockito BDDMockito Class Methods (Behavior-Driven Development Style)

Mockito BDDMockito
Mockito BDDMockito given()
Mockito BDDMockito willThrow()
Mockito BDDMockito willAnswer()
Mockito BDDMockito willReturn()
Mockito BDDMockito willDoNothing()
Mockito BDDMockito willCallRealMethod()
Mockito BDDMockito then()
Mockito BDDMockito.any()
Mockito BDDMockito.times()

Comments