-
Notifications
You must be signed in to change notification settings - Fork 38.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@MockitoSpyBean
requires existing bean instance to spy on
#33935
Comments
@MockitoSpyBean
is not equivalent to boot‘s @SpyBean
@MockitoSpyBean
is not equivalent to boot's @SpyBean
@MockitoSpyBean
is not equivalent to boot's @SpyBean
@MockitoSpyBean
cannot spy concrete runtime bean type
@MockitoSpyBean
cannot spy concrete runtime bean type@MockitoSpyBean
cannot create spy for concrete runtime bean type
Sooooo, this turned out to be an interesting one! 😎 Your original example is not doing what you think it's doing. The following modified version of your example fails with @ExtendWith(SpringExtension.class)
class SpyBeanTests {
// @MockitoSpyBean
@SpyBean
SubTestService testService;
@Test
void test() {
MockingDetails mockingDetails = Mockito.mockingDetails(testService);
MockName mockName = mockingDetails.getMockCreationSettings().getMockName();
assertSoftly(softly -> {
softly.assertThat(mockingDetails.isSpy()).as("is spy").isTrue();
softly.assertThat(mockName).as("mock name").hasToString("testService");
softly.assertThat(SubTestService.counter).as("instantiation count").isEqualTo(1);
softly.assertThat(testService.echo("test")).as("message").isEqualTo("@Bean :: test");
});
}
@Configuration
static class Config {
@Bean
TestService testService() {
return new SubTestService("@Bean");
}
}
static class TestService {
private final String prefix;
TestService(String prefix) {
this.prefix = prefix;
}
String echo(String str) {
return prefix + " :: " + str;
}
}
static class SubTestService extends TestService {
static int counter;
SubTestService() {
this("Default constructor");
}
SubTestService(String prefix) {
super(prefix);
counter++;
}
}
} If you run it, you'll see that there are multiple failures.
What's happening here is that Spring Boot's So, you effectively end up with two beans of type In other words, neither Please note that returning the most specific type from a |
@MockitoSpyBean
cannot create spy for concrete runtime bean type@MockitoSpyBean
requires existing bean instance to spy on
In light of the above findings, I have reworded the title of this issue and added a new |
@quaff related issue that I opened in the Spring Boot project and that was closed as it's desired behavior: spring-projects/spring-boot#43245 |
@sbrannen Thanks for your elaboration, I think
EDIT: I created #33965 to improve exception message. |
Overview
When an existing bean of the required type is not discovered in the bean factory, Spring Boot's
@SpyBean
creates a new instance to spy on by instantiating the required type using its default constructor.Whereas,
@MockitoSpyBean
requires that a bean of the required type exists and throws anIllegalStateException
if an appropriate bean cannot be found.Consequently,
@MockitoSpyBean
cannot be used to spy on a bean that does not exist.Original Description
@MockitoSpyBean
cannot spy concrete runtime bean type, but Spring Boot's@SpyBean
can.Example
Test fails with:
The workaround is changing the
@Bean
method to return the most specific type,SubTestService
in this example.The text was updated successfully, but these errors were encountered: