Mockito Inject real objects into private @Autowired fields
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Mockito is a popular mocking framework for unit tests in Java. However, there’s often confusion around how to use it to mock or inject real objects into private @Autowired fields in Spring-based applications. This article aims to demystify this process and provide clear examples and explanations.
Understanding the Problem
In Spring Framework, dependency injection allows the framework to control the creation of beans and their injection into components where they are needed. @Autowired is used to automatically inject beans by type. However, during unit testing, you might encounter a scenario where you need to inject a real object or a mocked instance into a private field annotated with @Autowired in order to isolate the test scenario.
Use Case for Mockito in Spring Tests
Suppose you have a service class which depends on a repository, and you need to test this service in isolation. Let’s consider an example:
Here, UserService has a private UserRepository field. During unit testing, you don’t want to use the actual repository as it would make the test an integration test and potentially slow and brittle.
Injecting Mocks into Private Fields
Mockito alone does not support injecting into private fields directly; this is where reflection comes in handy. By using reflection, we can bypass the access control checks and alter the private fields.
Using ReflectionTestUtils
Spring offers ReflectionTestUtils which is specifically designed for such use cases in tests. It provides methods to set private fields without needing direct access to them. Here’s how you can use it in a test:
In this setup, @MockBean creates a mock instance of UserRepository and replaces the bean in the application context, which is then injected into UserService.
When to Use Real Instances
Sometimes, you want to test the interaction between real components instead of mock interactions. For this, you can use @SpyBean to wrap a real bean with spying behavior.
Table summarizing key annotation interactions:
| Annotation | Usage |
@Autowired | Automatically inject beans by type. |
@MockBean | Creates a mock instance and adds/replaces the bean in the Spring application context. |
@SpyBean | Wraps the real bean in a spy to monitor real method calls while retaining the original behavior. |
@InjectMocks | Used by Mockito to inject mocked fields into the tested object automatically.
Not compatible with @Autowired. |
Advanced Scenario: Hybrid Approach using @SpringBootTest
There might be cases where you need a more integrated environment while still controlling certain bean definitions, such as when the application context setup is complex. In such cases, using @SpringBootTest along with mock definitions can be beneficial.
Here's a small illustration:
Conclusion
In conclusion, Mockito with Spring can be powerful, but one must understand when to use mocks, spies, or real beans. Utilizing tools like ReflectionTestUtils or annotations like @MockBean and @SpyBean, one can effectively write unit tests or slightly broader scoped integration tests, managing dependencies cleanly and ensuring tests remain focused on their target behavior.

