@ComponentScan not working in test with spring-boot-starter-test

Geyser14 picture Geyser14 · May 16, 2014 · Viewed 14.2k times · Source

I am attempting to test my @Service and @Repository classes in my project with spring-boot-starter-test and @Autowired is not working for the classes I'm testing.

Unit test:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = HelloWorldConfiguration.class
//@SpringApplicationConfiguration(classes = HelloWorldRs.class)
//@ComponentScan(basePackages = {"com.me.sbworkshop", "com.me.sbworkshop.service"})
//@ConfigurationProperties("helloworld")
//@EnableAutoConfiguration
//@ActiveProfiles("test")
// THIS CLASS IS IN src/test/java/ AND BUILDS INTO target/test-classes
public class HelloWorldTest {

    @Autowired
    HelloWorldMessageService helloWorldMessageService;

    public static final String EXPECTED = "je pense donc je suis-TESTING123";

    @Test
    public void testGetMessage() {
        String result = helloWorldMessageService.getMessage();
        Assert.assertEquals(EXPECTED, result);
    }
}

Service:

@Service
@ConfigurationProperties("helloworld")
// THIS CLASS IS IN /src/main/java AND BUILDS INTO target/classes
public class HelloWorldMessageService {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String  message) {
        this.message=message;
    }

}

The commented class annotations on the unit test represent the various things I've tried to get this working. The test and the project packages are in the same package paths and the @ComponentScan works fine from my entry point (@RestController class with main method). The service @ComponentScan's and @Autowire's fine in my @RestController class in the src/main/java side, but does not in the test. I am required to add it again as a @Bean in my @Configuration class in order for @Autowired to work. The class is otherwise in scope just fine and I can reference and instantiate it just fine from the test. The problem appears to be that @ComponentScan does not appear to correctly traverse multiple entries in my test runner classpath, in this case /target/test-classes and /target/classes.

The IDE I am using is IntelliJ IDEA 13.

UPDATE - here are HelloWorldRs and its config:

@RestController
@EnableAutoConfiguration
@ComponentScan
public class HelloWorldRs {

    //    SPRING BOOT ENTRY POINT - main() method
    public static void main(String[] args) {
        SpringApplication.run(HelloWorldRs.class);
    }

    @Autowired
    HelloWorldMessageService helloWorldMessageService;

    @RequestMapping("/helloWorld")
    public String helloWorld() {
        return helloWorldMessageService.getMessage();
    }

}

...

@Configuration
public class HelloWorldConfiguration {

    @Bean
    public Map<String, String> map() {
        return new HashMap<>();
    }

    // This bean was manually added as a workaround to the @ComponentScan problem
    @Bean
    public HelloWorldMessageService helloWorldMessageService() {
        return new HelloWorldMessageService();
    }

    // This bean was manually added as a workaround to the @ComponentScan problem
    @Bean
    public HelloWorldRs helloWorldRs() {
        return new HelloWorldRs();
    }
}

Answer

Marwin picture Marwin · Oct 24, 2017

First, I'd recommend to use a newer @RunWith(SpringRunner.class) but that makes no difference, it is just shorter (and recommended).

Second, from the @EnableAutoConfiguration I see that you are using spring boot - which is certainly a good thing. There are some good reasons why not to use @ComponentScan directly. Can you try the following?

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes=YourApplication_or_other_Configuration.class)
public class HelloWorldTest {
... etc.