Replacing Deprecated @MockBeans in Spring Boot 3.4+
Problem Statement
Since Spring Boot 3.4.0, the @MockBean
and @MockBeans
annotations have been deprecated in favor of the new @MockitoBean
annotation. This change affects developers who use these annotations to create custom meta-annotations for group mocking multiple dependencies in tests.
The challenge arises when migrating existing compositions like:
@MockBeans({
@MockBean(ServiceA.class),
@MockBean(ServiceB.class),
@MockBean(ServiceC.class)
})
Without a direct @MockitoBeans
replacement, developers with numerous mocks (20+) face tedious manual declarations in each test class.
Solution
With Spring Boot 3.4+, replace class-level @MockBeans
with @MockitoBean
using its types
attribute to specify multiple beans. This approach maintains the grouped mocking behavior while using the new annotation system.
Migration Steps
- Replace
@MockBeans
with@MockitoBean
- Convert individual
@MockBean
entries to thetypes
array - Update package imports
Here's how to rewrite the custom annotation:
import org.springframework.test.context.bean.override.mockito.MockitoBean;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// Old approach: @MockBeans({@MockBean(ServiceA.class), ...})
@MockitoBean(types = {ServiceA.class, ServiceB.class, ServiceC.class})
public @interface MyMocksTest {
}
Field-Level Migration
For individual field mocks:
// Old: @MockBean
@MockitoBean
private ServiceA serviceA;
// Spy beans replacement
@MockitoSpyBean // Replaces @SpyBean
private ServiceB serviceB;
Key Differences Explained
- Class-Level Support:
@MockitoBean(types = {...})
replaces the deprecated@MockBeans
container - Repeatable Annotation:
@MockitoBean
can be repeated at type level instead of using a container:java@MockitoBean(ServiceA.class) @MockitoBean(ServiceB.class) public @interface MyMocksTest {}
- New Location: Import from
org.springframework.test.context.bean.override.mockito
- Same Behavior: Null returns for unstubbed methods and automatic application context integration remain unchanged
Compatibility Note
While deprecated annotations remain functional until Spring Boot 3.5, migrating avoids technical debt
Additional Recommendations
- Group Common Mocks: Organize mock definitions by module or functionalityjava
@MockitoBean(types = {PaymentService.class, InvoiceService.class}) public @interface FinancialMocks {}
- Custom Qualifiers: For beans needing qualification, use
name
attribute:java@MockitoBean(value = "mainDataSource", types = DataSource.class)
- Annotation Composition: Combine with other test annotations:java
@SpringBootTest @MyMocksTest @ActiveProfiles("test") public class MyIntegrationTest { ... }
Conclusion
Migrating from deprecated @MockBeans
to @MockitoBean
is straightforward using the types
attribute for class-level definitions. This approach maintains test conciseness while adopting Spring Boot 3.4+'s improved mocking strategy. Implement these changes before the deprecated annotations are removed in future versions.