Overview

Due to the deprecation of @MockBean and @SpyBean in favor of Spring Framework's new @MockitoBean and @MockitoSpyBean support, several users have raised issues in the Spring Framework issue tracker regarding incompatibilities between the two sets of annotations.

Although incompatibilities are to be expected, it is not immediately clear to users what the differences are.

To address that, the Framework team proposes that the Boot team introduce a new section in the Mocking and Spying Beans section of the reference docs that lists known differences and potential migration strategies.

This could perhaps be addressed via a "compatibility matrix" for the 4 annotations.

Since the deprecation of @MockBean and @SpyBean and the migration to @MockitoBean and @MockitoSpyBean are specific to Boot, the Framework team feels the migration/compatibility documentation would best reside in Boot's reference docs.

Ideally, members of the Boot and Framework teams could collaborate on compiling the compatibility matrix, and I'd be happy to assist with that.

Related Issues

  • 43282

  • https://github.com/spring-projects/spring-framework/issues/33925
  • https://github.com/spring-projects/spring-framework/issues/33934
  • https://github.com/spring-projects/spring-framework/issues/33935
  • etc.

Comment From: snicoll

the Framework team proposes that the Boot team introduce a new section in the Mocking and Spying Beans section of the reference docs

I don't recall such a discussion. FWIW, I believe that the reference documentation is the wrong place for this as it is related to upgrade considerations. Before we get going, we would need to see what if, if any, will be implemented in Spring Framework.

Comment From: philwebb

I agree with @snicoll, we generally keep this kind of thing out of the reference docs. However, we could either improve our release notes or add another "migrating" page to the wiki.

Comment From: philwebb

Putting on hold for a little while because we'd like to know how https://github.com/spring-projects/spring-framework/issues/33925 will play out.

Comment From: philwebb

https://github.com/spring-projects/spring-framework/issues/33925 has now been fixed.

Comment From: wilkinsona

We haven't seen much need for this recently, so I'm guessing that what's already out there is meeting people's needs. We can reconsider if that situation changes.

Comment From: SimoneGiusso

We haven't seen much need for this recently, so I'm guessing that what's already out there is meeting people's needs. We can reconsider if that situation changes.

Out there where?

Comment From: bclozel

@SimoneGiusso The Framework team added more docs in the reference documentation. If you think something is missing, please create a new issue.

Comment From: SimoneGiusso

@SimoneGiusso The Framework team added more docs in the reference documentation. If you think something is missing, please create a new issue.

What is missing is a migration guide for the annotations. This is already well pointed out in the description. For example the problem raised in https://github.com/spring-projects/spring-framework/issues/33934. This is not mentioned even in the Spring Boot 4.0 Migration Guide

Ad @wilkinsona said, of course everything is out there because it's "enough" navigating through the GitHub issues, but then what's the point of collecting information in a migration guide?

I won't resume a duplicate of this issue because I interpret the closure of this one as a no intention to document the differences between the two annotations.

Spring boot 4 has just came out. I'm sure many people will realize that simply replace @MockBean with @MockitoBean won't be enough in some cases, but this will be now forced with this new version.

Cheers

Comment From: bclozel

@SimoneGiusso the issue you are pointing to has a lot of comments and different bits of information. From migration strategies, to well known limitations and more recent improvements.

I am also a Spring Framework team member. By pointing to the Framework issue tracker, I meant to ask you to explain the issues you encountered while upgrading and listing the points you wished the upgrade guide explained better.

We can of course consider that in the Spring Boot upgrade notes as suggested by this issue.

Right now this isn't really actionable because I am not sure how the Spring Boot upgrade guide should be updated. Is a link to the Framework reference docs section enough? Can you explain what is missing so that the Framework and Boot teams can write it?

Please add a new comment here listing what you are expecting in more details. Explaining your upgrade experience and the problems you ran into can also help shape that guide.

Comment From: SimoneGiusso

@SimoneGiusso the issue you are pointing to has a lot of comments and different bits of information. From migration strategies, to well known limitations and more recent improvements.

Exactly, that's why it makes even more sense to wrap up all the information. But I can explain my specific use case:

I've started not a long time after this issue has been created, to migrate the annotations @MockBean with @MockitoBean and saw my tests have started to break.

Noticing this open issue, and the non urgency to replace these deprecated annotations, I wanted to wait the spring-boot team to provide guidelines, on how to manage the incompatibilities (who better than spring boot team can suggest?)

My problem in particular was about using a class annotated with @Configuration having declared mocked beans with @MockBean annotation, as these classes needed to be mocked in all the integrations tests.

Now, I understand why tests break with @MockitoBean annotation and ways to solve the problem, but not because this is mentioned in some documentation, rather because I invested time in navigating through the GitHub issues, confirming that the problem was already known by the community.

When something gets deprecated, I'd expect to have some guidelines, in how it can be replaced. I understand that it may be difficult and maybe not possible at first to catch all the use cases and incompatibilities, but the issue I shared before, confirm the importance of this specific problem, since it has several votes on it.

This was my experience with the upgrade. What I'd expect after a team got some feedback from the community during the "deprecation window", is to provide guidance in replacing the annotation since the @MockBean annotation is not even more available in spring boot 4.

I would expect, and it may be better, have this guideline in the migration guide rather than in the @MockitoBean reference page to avoid having references to something is not more present in the framework, for which, new spring users, may not be even interested in. And it looks like there is already a dedicated section for this topic in the migration guide.

Comment From: bclozel

My problem in particular was about using a class annotated with @Configuration having declared mocked beans with @MockBean annotation, as these classes needed to be mocked in all the integrations tests.

That's the piece of information I was missing. I'm probably not the most knowledgeable person about this particular feature, and I'm not sure what the "compatibility matrix" was referring to in the comments above. So I've tried to gather useful information in a dedicated section that we could add to our wiki migration guide. What do you think? Hopefully we can resolve this in a constructive fashion.

Upgrading Testing Features

@MockBean and @SpyBean deprecations

Spring Boot's @MockBean and @SpyBean support has been deprecated in this release, in favor of @MockitoBean and @MockitoSpyBean support. You can temporarily work around this deprecation by adding @SuppressWarnings("removal") in your tests, or using a custom annotation if there are many occurrences in your codebase.

While working around the deprecation can be useful, it is only a temporary situation as @MockBean and @SpyBean support will be removed in the future. If your tests are using @MockBean and @SpyBean as fields in test classes, you can consider a direct replacement:

@SpringBootTest
class ApplicationTests {

    @MockitoBean
    private GreetingService greetingService;

    @Test
    void check() {
        // ...
    }
}

Behavior is explained in more details in the Spring Framework reference docs section named @MockitoBean and @MockitoSpyBean.

There is a key difference between @MockBean/@SpyBean and @MockitoBean/@MockitoSpyBean. The new annotations are allowed to be used as fields in test classes, but not in @Configuration classes. Using those in @Configuration is a way to declare a set of mocked beans without repeating those fields in different test classes:

@SpringBootTest
@Import(TestConfig.class)
class ApplicationTests {

    @Test
    void check() {
        // ...
    }
}

@TestConfiguration
public class TestConfig {
    @MockBean
    private UserService userService;

    @MockBean
    private OrderService orderService;

    @MockBean
    private PrintingService ps1;
}

Instead, those "shared mocked beans" can be declared directly on the test class like this:

@SpringBootTest
@MockitoBean(types = {OrderService.class, UserService.class}) 
@MockitoBean(name = "ps1", types = PrintingService.class) 
class ApplicationTests {

    @Test
    void check() {
        // ...
    }
}

If declaring those on the test class itself (or any super-class in its hierarchy) is not practical, you can also consider a custom annotation:

@SpringBootTest
@SharedMocks
class ApplicationTests {

    @Test
    void check() {
        // ...
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MockitoBean(types = {OrderService.class, UserService.class}) 
@MockitoBean(name = "ps1", types = PrintingService.class) 
public @interface SharedMocks {
}