Using @MockBean to Mock Dependencies in Spring Boot Tests
📖 Scenario: You are building a simple Spring Boot application that manages books. You want to write a test for the BookService class, but it depends on BookRepository which accesses the database. To test BookService without using the real database, you will use @MockBean to create a fake BookRepository.
🎯 Goal: Write a Spring Boot test class that uses @MockBean to mock the BookRepository dependency. Then write a test method that verifies BookService returns the expected book title.
📋 What You'll Learn
Create a Book class with id and title fields
Create a BookRepository interface with a method findById(Long id)
Create a BookService class that uses BookRepository to get a book by id
Write a test class using @SpringBootTest and @MockBean to mock BookRepository
Write a test method that mocks findById to return a sample book and asserts the service returns the correct title
💡 Why This Matters
🌍 Real World
Mocking dependencies in tests helps you isolate the code you want to test. This avoids using real databases or external services, making tests faster and more reliable.
💼 Career
Understanding @MockBean is essential for writing effective unit and integration tests in Spring Boot applications, a common requirement in Java backend development jobs.
Progress0 / 4 steps
1
Create the Book class and BookRepository interface
Create a class called Book with Long id and String title fields and their getters. Then create an interface called BookRepository with a method Optional findById(Long id).
Spring Boot
Hint
Use a simple Java class for Book with constructor and getters. The repository is an interface with one method returning Optional.
2
Create the BookService class with a dependency on BookRepository
Create a class called BookService with a private final BookRepository bookRepository field. Add a constructor to inject BookRepository. Add a method String getBookTitle(Long id) that returns the book title by calling bookRepository.findById(id) and returning the title or "Not Found" if empty.
Spring Boot
Hint
Inject BookRepository via constructor. Use Optional.map() to get title or return "Not Found".
3
Create the test class and mock BookRepository with @MockBean
Create a test class called BookServiceTest annotated with @SpringBootTest. Inside, declare a @MockBean field of type BookRepository named bookRepository. Also declare an @Autowired field of type BookService named bookService. Write a test method testGetBookTitle() annotated with @Test.
Spring Boot
Hint
Use @MockBean to create a fake BookRepository and @Autowired to inject BookService. Add a test method annotated with @Test.
4
Mock findById and assert getBookTitle returns expected title
Inside the testGetBookTitle() method, use when(bookRepository.findById(1L)) to return Optional.of(new Book(1L, "Spring in Action")). Then call bookService.getBookTitle(1L) and assert it equals "Spring in Action" using assertEquals.
Spring Boot
Hint
Use Mockito's when(...).thenReturn(...) to mock the repository method. Use assertEquals to check the service returns the mocked title.
Practice
(1/5)
1. What is the main purpose of using @MockBean in a Spring Boot test?
easy
A. To replace a real Spring bean with a mock for isolated testing
B. To create a new Spring bean in the application context
C. To automatically inject real dependencies into the test
D. To configure database connections for integration tests
Solution
Step 1: Understand the role of @MockBean
@MockBean is used to replace a real bean in the Spring context with a mock version during tests.
Step 2: Identify the testing benefit
This replacement helps isolate the component under test by faking dependencies, avoiding real implementations.
Final Answer:
To replace a real Spring bean with a mock for isolated testing -> Option A
Quick Check:
@MockBean replaces real beans [OK]
Hint: Remember: @MockBean fakes dependencies for focused tests [OK]
Common Mistakes:
Thinking @MockBean creates new beans instead of replacing
Confusing @MockBean with @Autowired injection
Using @MockBean to configure real database connections
2. Which of the following is the correct way to declare a mock bean for a service named UserService in a Spring Boot test?
easy
A. @MockBean UserService userService = new UserService();
B. @MockBean private UserService userService;
C. @MockBean public void userService();
D. @MockBean UserService userService();
Solution
Step 1: Recall @MockBean declaration syntax
@MockBean is used as an annotation on a field to create a mock instance injected by Spring.
Step 2: Check each option
@MockBean private UserService userService; correctly declares a private field annotated with @MockBean. Other options use invalid syntax such as instantiating manually with new or declaring as methods.
Final Answer:
@MockBean private UserService userService; -> Option B
When running this test, it fails with a NullPointerException. What is the most likely cause?
medium
A. The orderService is not mocked properly because it is private
B. The verify method is called before placeOrder()
C. The placeOrder() method is final and cannot be mocked
D. The @MockBean annotation was not processed because the test class lacks @SpringBootTest
Solution
Step 1: Check test setup requirements
@MockBean requires Spring Boot test context to process annotations, usually via @SpringBootTest or similar.
Step 2: Identify cause of NullPointerException
If @MockBean is not processed, orderService remains null, causing NPE when calling placeOrder().
Final Answer:
The @MockBean annotation was not processed because the test class lacks @SpringBootTest -> Option D
Quick Check:
@MockBean needs Spring context [OK]
Hint: Always use @SpringBootTest to enable @MockBean processing [OK]
Common Mistakes:
Assuming private fields can't be mocked
Misordering verify and method calls
Not realizing final methods can't be mocked (but not cause NPE here)
5. You have a Spring Boot service NotificationService that depends on EmailSender. You want to test NotificationService without sending real emails. Which setup correctly uses @MockBean to mock EmailSender and verify sendEmail() was called once during the test?
hard
A. Use @MockBean EmailSender emailSender; in the test class, call notificationService.notify(), then verify with verify(emailSender, times(1)).sendEmail();
B. Use @Autowired EmailSender emailSender; and call sendEmail() directly in the test
C. Create a new EmailSender instance manually and inject it into NotificationService
D. Use @MockBean NotificationService notificationService; and verify sendEmail() on it
Solution
Step 1: Mock the dependency EmailSender
Use @MockBean on EmailSender to replace the real bean with a mock in the test context.
Step 2: Call the method under test and verify interaction
Call notificationService.notify() which uses EmailSender internally, then verify sendEmail() was called once on the mock.
Final Answer:
Use @MockBean EmailSender emailSender; call notificationService.notify(); verify sendEmail() called once -> Option A