Yes, we're now running our Black Friday Sale. All Access and Pro are 33% off until 2nd December, 2025:
What is @MockitoSpyBean in Spring
Last updated: November 27, 2025
1. Introduction
When testing Spring Boot applications, it’s common to replace some beans in the application context with mock or spy objects. This allows us to intercept method calls, verify interactions, or override behavior for specific components — all without executing the underlying logic.
Starting with Spring Framework 6.2, a new annotation @MockitoSpyBean was introduced. This addition is part of a broader effort to integrate Mockito more tightly with the Spring TestContext framework, offering developers finer control and more predictable behavior when working with spies.
In this article, we’ll explore what @MockitoSpyBean is, how it differs from the legacy @SpyBean, and how we can use it in modern Spring tests. We’ll also look at a few practical code examples and discuss migration considerations for existing test suites.
2. What is @MockitoSpyBean?
The @MockitoSpyBean annotation is used in Spring tests to wrap an existing bean from the application context in a Mockito spy.
Unlike mocks, spies do not completely replace the original bean. Instead, they allow partial mocking — the real methods are invoked unless explicitly stubbed. This makes them ideal for scenarios where we want to verify method calls or tweak behavior without discarding the bean’s real implementation.
Under the hood, Spring creates the real bean early in the test lifecycle and then wraps it with a Mockito spy. This means that the bean’s dependencies, lifecycle callbacks, and initialization logic still run as usual.
It’s also part of a broader change in Spring Framework 6.2, which introduced the @MockitoBean, @MockitoSpyBean, and related infrastructure, replacing the older @MockBean and @SpyBean with a unified and more flexible design.
3. @SpyBean vs @MockitoSpyBean
Before @MockitoSpyBean existed, we typically used @SpyBean to achieve similar results. At first glance, both annotations seem interchangeable – they allow us to create spies for Spring beans and use Mockito’s verification API. However, their behavior under the hood is different, and this difference becomes significant in complex or proxy-heavy applications.
The older @SpyBean creates a new spy instance using Mockito and then replaces the original bean in the Spring context with that instance. This approach works well for most tests, but this replacement can occasionally disrupt the bean’s proxy chain or lifecycle, especially when using AOP or transactional beans.
On the other hand, @MockitoSpyBean works differently. Instead of creating a replacement, it retrieves the real bean that Spring has already created and wraps it with a spy. As a result, the bean’s internal configuration and proxies remain intact, and its behavior in the test is closer to what happens in production.
This subtle change makes @MockitoSpyBean proxy-safe and more predictable in modern Spring applications. It’s also worth noting that the older annotations are now considered legacy and are expected to be removed in future major Spring versions.
4. @MockitoSpyBean in Action
Now that we understand how @MockitoSpyBean works, let’s write some code to see it in action. Let’s use a previously available code example to see how we migrate the legacy annotations:
@Autowired
OrderRepository orderRepository;
@MockitoSpyBean
NotificationService notificationService;
@MockitoSpyBean
OrderService orderService;
@Test
void givenNotificationServiceIsUsingSpyBean_whenOrderServiceIsCalled_thenNotificationServiceSpyBeanShouldBeInvoked() {
Order orderInput = new Order(null, "Test", 1.0, "17 St Andrews Croft, Leeds ,LS17 7TP");
doReturn(true).when(notificationService)
.raiseAlert(any(Order.class));
Order order = orderService.save(orderInput);
Assertions.assertNotNull(order);
Assertions.assertNotNull(order.getId());
verify(notificationService).notify(any(Order.class));
}
As shown in the code above, migrating from the legacy annotations is straightforward. We just replaced the old @SpyBean annotations with @MockitoSpyBean, and the test continued to work without any other changes.
This highlights one of the key benefits of the new annotation. It serves as a drop-in replacement for existing tests while providing a more reliable, framework-level integration between Mockito and the Spring TestContext.
5. Conclusion
In this article, we explored the new @MockitoSpyBean annotation introduced in Spring Framework 6.2.
It provides a modern, framework-level alternative to the older @SpyBean, offering improved functionality, better integration with Spring’s proxy system, and more consistent behavior across different test contexts. By wrapping – rather than replacing – real beans, @MockitoSpyBean preserves the bean’s lifecycle, dependencies, and proxies. This makes it especially useful for integration tests where we want to validate real application logic while retaining the ability to observe or stub specific interactions.
As the Spring ecosystem continues to evolve, @MockitoSpyBean is the recommended choice for new projects and will likely become the standard for spy-based testing in upcoming Spring versions.
As always, the code from the article is available over a GitHub repository.















