spring-bootspring-boot-test

Integration-testing a Spring Boot @Service without SpringBootApplication


I have a standalone Spring Boot @Service in its own repository. The repository is a "helper library" and does not itself contain a @SpringBootApplication or any @RestController. The Service uses an Autowired S3Template from Spring Cloud AWS.

How can I write integration tests of the @Service without using @SpringBootApplication or having a main class?

I've seen several related answers involving @TestConfiguration and other annotations, but am struggling to put the pieces together and get this working with Spring Boot 3.3.x.

I have produced a minimal, reproducible example (Spring Boot 3.3, JDK 21) at:

https://github.com/solomonbrjnih/so-service-no-application

As-is, this will run cleanly with passing tests using mvn clean test -- however, only because I have added a @SpringBootApplication in src/test. This does not seem like the idiomatic way, and this approach will break if I attempt to use Maven Failsafe Plugin to run integration tests "the right way".

To be clear, I do not want to do any mocking here--I want to test the real service as-is, in this case against an actual Amazon S3 (development) environment.

What I have tried:

I've tried using @TestConfiguration, but am getting errors related to autowiring/beans:

// TestConfig.java
package foo.demo;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;

@TestConfiguration
public class TestConfig {

    @Bean
    public DemoService service() {
        return new DemoService();
    }
}
// DemoApplicationTests.java
...
@ExtendWith(SpringExtension.class)
@Import(TestConfig.class)
class DemoApplicationTests {

    @Autowired
    private DemoService service;
...

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'service': Unsatisfied dependency expressed through field 's3Template': No qualifying bean of type 'io.awspring.cloud.s3.S3Template' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}


Solution

  • Spring Boot docs contains a guide for Creating a Multi Module Project. Section "Testing the Service Component" contains

    @SpringBootTest("service.message=Hello")
    public class MyServiceTest {
    
      @Autowired
      private MyService myService;
    
      @Test
      public void contextLoads() {
        assertThat(myService.message()).isNotNull();
      }
    
      @SpringBootApplication // this is the one you need
      static class TestConfiguration {
      }
    }
    

    An alternative is to add this to a separate class TestConfiguration

    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class TestConfiguration {
    }
    

    If any configuration is required, put this in an application.yml or application.properties in test/resources.