@Qualifier support was recently added for @TestBean, MockitoBean, and MockitoSpyBean fields; however, when the name of the annotated field exactly matches the name of the bean being overridden or spied the field name is not currently used as a fallback qualifier, in contrast to regular injection points (such as @Autowired fields).

For example, the following currently only passes with the presence of @Qualifier("exampleService").

@SpringJUnitConfig
class MockitoBeanFallbackQualifierTests {

    @Qualifier("exampleService")
    @MockitoBean
    ExampleService exampleService;

    @Test
    void test() {
        when(exampleService.greeting()).thenReturn("test");
        assertThat(exampleService.greeting()).isEqualTo("test");
    }

    @Configuration
    static class Config {

        @Bean
        ExampleService exampleService() {
            return () -> "prod";
        }

        @Bean
        ExampleService exampleService2() {
            return () -> "prod2";
        }
    }

    interface ExampleService {
        String greeting();
    }
}

Whereas, ideally we should be able to remove @Qualifier("exampleService") and have the field name ("exampleService") be used as the fallback qualifier.

Comment From: snicoll

While I agree this is a good idea, it makes the computation of the cache so much more complex. It's unclear whether we'll be able to figure out from the set of annotations defined on the field what the qualifier actually is (Spring Boot didn't AFAIK). If we use the name of the field as a fallback, two tests that intend to mock the same service may create two contexts if we're unable to figure out what the actual bean might be.

Comment From: snicoll

Brainstorming with @jhoeller, it turns out we don't really have much of a choice and the name of the field must be taken into account when by-type semantic is at play. We'll have to carefully document this.

Comment From: sbrannen

It's unclear whether we'll be able to figure out from the set of annotations defined on the field what the qualifier actually is (Spring Boot didn't AFAIK). If we use the name of the field as a fallback, two tests that intend to mock the same service may create two contexts if we're unable to figure out what the actual bean might be.

Indeed, that could become a bit of a chicken-and-egg problem: a question of whether the metadata we can collect upfront results in potentially conflicting metadata that in end the would actually select the same bean.

Brainstorming with @jhoeller, it turns out we don't really have much of a choice and the name of the field must be taken into account when by-type semantic is at play. We'll have to carefully document this.

Carefully documenting it sounds like a good plan.

Thanks for brainstorming and sharing the rationale.