Introduction
Behavior-Driven Development (BDD) encourages writing tests in a more natural, readable language that describes the behavior of the application. Mockito provides the BDDMockito
class, which allows you to use BDD-style syntax for stubbing and verifying interactions. This tutorial will demonstrate how to use BDDMockito
to write more readable and expressive tests.
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
to handle stubbing and verifying interactions.
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
Creating Mocks with
@Mock
:- The
@Mock
annotation creates a mock instance of theBookRepository
interface. This mock instance can be used to simulate the behavior of theBookRepository
in a controlled way.
- The
Injecting Mocks with
@InjectMocks
:- The
@InjectMocks
annotation injects the mockBookRepository
into theLibraryService
instance to provide a controlled test environment. This allows theLibraryService
methods to be tested in isolation from the actualBookRepository
implementation.
- The
Using BDDMockito:
given()
: Thegiven(bookRepository.findBookByTitle(title)).willReturn(book);
method configures the mockBookRepository
to return a specificBook
object when thefindBookByTitle
method is called with the specified title.then()
: Thethen(bookRepository).should().saveBook(any(Book.class));
method verifies that thesaveBook
method was called on theBookRepository
with anyBook
object.argThat()
: Thethen(bookRepository).should().saveBook(argThat(book -> book.getTitle().equals("Mockito in Action") && book.getAuthor().equals("Ramesh Fadatare")));
method verifies that thesaveBook
method was called on theBookRepository
with aBook
object that matches the specified title and author.
Additional Scenarios
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
- Verifying No Interactions:
- The
then(bookRepository).shouldHaveNoInteractions();
method verifies that no interactions occurred with theBookRepository
mock object. This ensures that theBookRepository
was not used during the test.
- The
Scenario: Verifying Method Call Order
In this scenario, we will demonstrate how to verify the order of method calls using BDDMockito
.
@Test
public void testMethodCallOrder() {
// Given
String title = "Mockito in Action";
Book book = new Book(title, "Ramesh Fadatare");
given(bookRepository.findBookByTitle(title)).willReturn(book);
// When
libraryService.addBook(title, "Ramesh Fadatare");
libraryService.getBookByTitle(title);
// Then
InOrder inOrder = inOrder(bookRepository);
then(bookRepository).should(inOrder).saveBook(any(Book.class));
then(bookRepository).should(inOrder).findBookByTitle(title);
}
Explanation
- Verifying Method Call Order:
- The
InOrder inOrder = inOrder(bookRepository);
statement creates anInOrder
object to verify the order of interactions with theBookRepository
mock object. - The
then(bookRepository).should(inOrder).saveBook(any(Book.class));
andthen(bookRepository).should(inOrder).findBookByTitle(title);
methods verify that thesaveBook
method was called before thefindBookByTitle
method on theBookRepository
.
- The
Conclusion
Using BDDMockito
in Mockito allows you to write more readable and expressive tests that follow the Behavior-Driven Development (BDD) style. By using given()
, then()
, and other BDD-style methods, you can handle various scenarios and control the behavior of mock objects. This step-by-step guide demonstrated how to effectively use BDDMockito
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
Post a Comment
Leave Comment