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?
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.
You should use spring boot profiles:
Annotate your test configuration with @Profile("test"). Annotate your production configuration with @Profile("production"). Set production profile in your properties file: spring.profiles.active=production. 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.
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.
Success story sharing
@EnableAuthorizationServer
@Configuration
class onsrc/test/java
. Spring boot rules :-)@Configuration
, instead of overriding it all you can enable a specific spring boot profile (e.g. namedtest
) for your tests using the annotation@ActiveProfiles({"test", ...})
on your test class(es). Then a simpleif (Arrays.asList(environment.getActiveProfiles()).contains("test"))
on your@Configuration
will do.@TestConfiguration
.(instead of@Configuration
) like author mentioned, the Beans get picked up right. And I would prefere@Imort
over@SpringBootTest(classes=...)
, somehow I got wired behaivor in some cases where a Test with an extra@Import
worked and another without not. This hole Spring configuration for testing takes a lot of time to understand. puh