Spring boot ComponentScan excludeFIlters not excluding

Daniel Taub :

I am having a SimpleTest :

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SimpleTestConfig.class)
public class SimpleTest {
    @Test
    public void test() {
        assertThat(true);
    }
}

and a configuration for this test :

@SpringBootApplication
@ComponentScan(basePackageClasses = {
        SimpleTestConfig.class,
        Application.class
},
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = Starter.class))
public class SimpleTestConfig {
}

I am trying to exclude the Starter class

package application.starters;

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component
public class Starter {
    @PostConstruct
    public void init(){
        System.out.println("initializing");
    }
}

And the Application class looks like this :

package application;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import static org.springframework.boot.SpringApplication.run;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        run(Application.class, args);
    }
}

But for a very weird reason the Starter class is still getting initialized.

Can anyone explain why the ComponentScan excludeFilters is not excluding my Starter class ?

tkruse :

Each component scan does filtering individually. While you exclude Starter.class from SimpleTestConfig, SimpleTestConfig initializes Application, which does it's own @ComponentScan without excluding Starter. The clean way of using ComponentScan is for each ComponentScan to scan separate packages, that way each filter works fine. When 2 separate ComponentScans scan the same package (as in your tests), this does not work.

One way to trick this is to provide a mock Starter bean:

import org.springframework.boot.test.mock.mockito.MockBean;

public class SimpleTest {
    @MockBean
    private Starter myTestBean;
    ...
}

Spring will use that mock instead of the real class, thus the @PostConstruct method will not be called.

Other common solutions:

  • Do not directly use Application.class in any unit test
  • Use Spring profile and annotations such as @Profile("!TEST") on the Starter class
  • Use a spring Boot @ConditionalOn... annotation on the Starter class

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=437022&siteId=1