Hi,

hopefully I'm not doing anything wrong here. I assume that @TestComponent should be picked up when running tests with @SpringBootTest without further ado, but neither this

package com.example;

import org.springframework.boot.test.context.TestComponent;

@TestComponent
public class ToplevelTestComponent {

}

together with

package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ToplevelTestComponentNotWorkingTest {
    @Autowired
    ToplevelTestComponent toplevelTestComponent;

    @Test
    public void f() {
    }
}

nor this (nested version)

package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestComponent;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class NestedTestComponentNotWorkingTest {
    @TestComponent
    static class NestedTestComponent{
    }

    @Autowired
    NestedTestComponent nestedTestComponent;

    @Test
    public void f() {
    }
}

works. Both fail with org.springframework.beans.factory.NoSuchBeanDefinitionException. Sample project is attached: InitializrSpringbootProject.zip Tested with 1.4.0, 1.4.3 and 1.5.1.

Maybe it's a documentation issue, but I don't see my error…

Comment From: snicoll

Javadoc:

@Component that can be used when a bean is intended only for tests, and should be excluded from Spring Boot's component scanning.

Documentation:

To help prevent this, Spring Boot provides @TestComponent and @TestConfiguration annotations that can be used on classes in src/test/java to indicate that they should not be picked up by scanning.

What do you expect based on the doc?

Comment From: michael-simons

Exactly the example above: Annotating a pojo in src/test/java with only @TestComponent with the result that it gets picked up during test, not that I have to use both @Component and @TestComponent.

Comment From: michael-simons

If I have an @Component inside src/test/java, it get's picked up only during tests anyway, not during normal start. I cannot annotate any component inside src/main/java with @TestComponent having spring-boot-starter-test as test dependency.

Comment From: snicoll

I am not following, the doc states that it will not be picked up by component scan. Why do you want it to be picked up all the sudden then? @TestConfiguration aren't picked up by component scan either ...

Comment From: snicoll

Perhaps we could turn that one into a documentation enhancement. I am not excluding that @philwebb had something else in mind that I didn't get so it's certainly a good use of our time.

Comment From: michael-simons

Sadly, you gave up when I just understood the purpose of @TestComponent.

I'd recommend you separate it a bit from @TestConfiguration in the docs and state that @TestComponent facilitate the creation of @TestConfiguration.

(TBH: I wonder if @TestComponent belongs into the reference at all or should only be part of JavaDoc)

Thanks, @snicoll for the good discussion. Got it now.

Comment From: snicoll

The conversation on gitter was going in circles. If we've added that in the doc explicitly, I guess there's a reason I am missing anyway so we'll follow-up here for sure.

Comment From: snicoll

See also #6769 (in particular https://github.com/spring-projects/spring-boot/issues/6769#issuecomment-278794709)

Comment From: michael-simons

Hey, just a quick feedback from my colleague here, I tried to asked the questions about 41.3.2 in the docs as open as possible and he expressed the same expectations as I: @TestComponent would have the same visible result as @TestConfiguration (by visible result we mean have an impact in the application context, that is add to the configuration, appearing as bean (regardless if its component-scan or something else)). I think the dualism of @TestConfiguration is what causes or confusion with @TestComponent. Although @TestConfiguration is not picked by component scan, it has an impact.

Comment From: michael-simons

Very good change in the docs! Thanks.

Comment From: nightswimmings

I got the same confusion. If @TestComponent just filters out the component from the test context, I don't understand where it is used, so perhaps it would be better to focus on explaining when do you need such a feature. If I understand correctly by reading the docs, one uses @TestComponent to annotate a class that might be excluded by default and selectively importable via its TestConfiguration parent @Import for particular testclasses you need it. But then, whats the point on making it a @XComponent at all? Does @Import only accept configuration @XComponent classes perhaps? Or it is maybe because that way we don't need to remove annotations that signal the purpose of the class like Stereotypes in order to exclude them from the component scanning?

Comment From: nightswimmings

I mean imagine I have a custom class AuxiliarHelperForMyTests class, and I don't annotate it with either @Component or @TestComponent. It exactly behaves as the description of @TestComponent, so what is exactly the purpose of @TestComponent annotation, what does it give me as extra value?

Comment From: wilkinsona

A noted in the commit that closed this issue, @TestComponent is really an implementation detail so you should not be using it directly. It exists to enable the functionality provided by @TestConfiguration which is described in the documentation.

If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.

Comment From: nightswimmings

Ahh that explains why any mention was removed from latest documentation. Anyway, I did a deep testing and I will expose the case in the way my mind would have understood it, in case you accept the suggerence for documentation or anyone else comes to this ticket as I did. Please remove it if you consider it inappropiate. And excuses for mistaking the workflow if that is the case in beforehand:

If you have classes in test classpath that you want to explictly mark as Stereotypes (@Component) or @Configuration, but you don't want them loaded accross all tests by the component scanning, the solution is marking them additionally as @TestComponent and @TestConfiguration. This is the benefit (1) I see of these 2 new annotations.

Then you can use @Import on any particular test class to import any of both (BTW, it was hard to find out that Import works on Components as if they were @Beans from a @Configuration class). The curious thing is that @Import does not require classes to be annotated with either @Component or @Configuration to load them, hence the special @TestX marker versions are not justified as a device to exclude from classpath but mark as importable.

Remember static inner classes are not part of component-scanning when found within test classes, so using previous annotations as static inner classes inside a test class: - @TestConfiguration is loaded as if it was @Configuration, with the difference that it does not override primary configuration (i.e, if you use @Configuration, then you'll miss beans exposed in production). This is the benefit (2) I see, specific to @TestConfiguration. - An static inner class @Component is not automatically picked within test classes since Spring Boot 1.4, due to TestTypeExcludeFilter excluding them, and neither is @TestComponent. In this case, marking the component with @TestComponent is only useful for clarity purposes, for the component requires an @Import on the outer class to be picked anyways, and import does not require any annotation on imported class in order to process it as a configuration/component class as explained before.