55
votes

On my spring boot application I want to override just one of my @Configuration classes with a test configuration (in particular my @EnableAuthorizationServer @Configuration class), on all of my tests.

So far after an overview of spring boot testing features and spring integration testing features no straightforward solution has surfaced:

  • @TestConfiguration: It's for extending, not overriding;
  • @ContextConfiguration(classes=…​) and @SpringApplicationConfiguration(classes =…​) let me override the whole config, not just the one class;
  • An inner @Configuration class inside a @Test is suggested to override the default configuration, but no example is provided;

Any suggestions?

3

3 Answers

71
votes

Inner test configuration

Example of an inner @Configuration for your test:

@RunWith(SpringRunner.class)
@SpringBootTest
public class SomeTest {

    @Configuration
    static class ContextConfiguration {
        @Bean
        @Primary //may omit this if this is the only SomeBean defined/visible
        public SomeBean someBean () {
            return new SomeBean();
        }
    }

    @Autowired
    private SomeBean someBean;

    @Test
    public void testMethod() {
        // test
    }
}

Reusable test configuration

If you wish to reuse the Test Configuration for multiple tests, you may define a standalone Configuration class with a Spring Profile @Profile("test"). Then, have your test class activate the profile with @ActiveProfiles("test"). See complete code:

@RunWith(SpringRunner.class)
@SpringBootTests
@ActiveProfiles("test")
public class SomeTest {

    @Autowired
    private SomeBean someBean;

    @Test
    public void testMethod() {
        // test
    }
}

@Configuration
@Profile("test")
public class TestConfiguration {
    @Bean
    @Primary //may omit this if this is the only SomeBean defined/visible
    public SomeBean someBean() {
        return new SomeBean();
    }
}

@Primary

The @Primary annotation on the bean definition is to ensure that this one will have priority if more than one are found.

12
votes

You should use spring boot profiles:

  1. Annotate your test configuration with @Profile("test").
  2. Annotate your production configuration with @Profile("production").
  3. Set production profile in your properties file: spring.profiles.active=production.
  4. Set test profile in your test class with @Profile("test").

So when your application starts it will use "production" class and when test stars it will use "test" class.

If you use inner/nested @Configuration class it will be be used instead of a your application’s primary configuration.

2
votes

I recently had to create a dev version of our application, that should run with dev active profile out of the box without any command line args. I solved it with adding this one class as a new entry, which sets the active profile programmatically:

package ...;

import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;

@Import(OriginalApplication.class)
public class DevelopmentApplication {
    public static void main(String[] args) {
        SpringApplication application =
            new SpringApplication(DevelopmentApplication.class);
        ConfigurableEnvironment environment = new StandardEnvironment();
        environment.setActiveProfiles("dev");
        application.setEnvironment(environment);
        application.run(args);
    }
}

See Spring Boot Profiles Example by Arvind Rai for more details.