4

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();
    }
}
Geyser14
  • 1,385
  • 3
  • 14
  • 32
  • 1
    What does `HelloWorlsRs` look like? – geoand May 16 '14 at 17:53
  • Your test case isn't a configuration, and all of those commented things are irrelevant on it. – chrylis -cautiouslyoptimistic- May 16 '14 at 18:52
  • see updated post for HelloWorldRs, etc. – Geyser14 May 19 '14 at 22:56
  • 1
    What happened? Did you fix you problem? How? – David Newcomb Sep 07 '15 at 10:23
  • From the `@EnableAutoConfiguration` I see that you are using spring-boot - which is certainly a good thing. Do you have a `@SpringBootApplication` in your project? Can you try to annotate your test as `@SpringBootTest`? – Marwin Oct 24 '17 at 07:35
  • `HelloWorldConfiguration` is not a `@SpringBootApplication` so spring Boot will not be used to start the context. – Dave Syer Oct 25 '17 at 18:19
  • Is there a reason you don’t want to use `@SpringBootApplication`? If not I would use it. Otherwise your main config class is missing `@Configuration`. – Dave Syer Oct 27 '17 at 10:54
  • No, I see I'm missing that. This was an older post and as soon as I get a moment I'm going get the code setup and test it again and update this post. (I'm optimistic). A very boneheaded thing to miss but I'll own up to it if I need to! – Geyser14 Oct 27 '17 at 16:57

3 Answers3

3

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.
Marwin
  • 2,655
  • 1
  • 19
  • 17
  • `@SpringBootTest` was recognizing the bean but was facing issue at run time. Adding `@EnableAutoConfiguration` helped bean instantiation issue, bean was in different package which I had to specify using `@ComponentScan` – Shrikant Prabhu Jan 13 '22 at 18:44
2

I don't know if this will turn out to be the solution, but don't use the default package (i.e. don't put *.java in "src/main/java" directly), and definitely don't use a @ComponentScan or @EnableAutoConfiguration in the default package. You will end up killing your application on startup as it tries to scan everything on the classpath (including all the Spring libraries).

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • point taken - just trying to get the components to load therefore the attempt to load from src/main/java to make sure nothing was missed – Geyser14 Oct 24 '17 at 22:10
0

SpringBoot 2.7.3, JUnit 5.8.2

If you want to have full control about the spring's configuration (and not rely on the hidden magic of auto configuration) I suggest to create an explicit configuration class:

@ComponentScan(basePackages = { "my.package.to.scan" })
public class MySpringTestConfig
{
    // just for spring configuration annotations
}

and reference it in your test class:

@ContextConfiguration(classes = { MySpringTestConfig.class })
@ExtendWith({ SpringExtension.class })
class MySpringTest
{
    ...
}
Heri
  • 4,368
  • 1
  • 31
  • 51