Reputation: 9488
I'm in the process of moving all of my Spring Configurations to Java code. I've run into a problem where I now want to set which profile I am using based on a command line switch or maven profile, etc... I also want to avoid having to place all of the same annotations on each of my test classes. This is not a web application, but rather a functional test suite.
Here is my attempt:
public class CompanyApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(final ConfigurableApplicationContext applicationContext) {
final AnnotationConfigApplicationContext rootContext = new AnnotationConfigApplicationContext();
rootContext.getEnvironment().setActiveProfiles(System.getProperty("spring.profile.active", "local"));
rootContext.register(LocalConfiguration.class, SauceLabsConfiguration.class);
}
}
Then I have my tests annotated with the following:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CompanyApplicationContextInitializer.class)
However when I attempt to run my tests, my autowired pieces are not being located. Am I on the right track at all? How can I wire in this class to programatically set my ApplicationContext?
Upvotes: 1
Views: 7006
Reputation: 1483
The problem with your example above is that you're passing an ApplicationContextInitializer class @ContextConfiguration#classes. The #classes attribute is intended to accept classes marked with Spring's @Configuration annotation.
ApplicationContextInitializer is intended for use primarily in web applications, where it is difficult to get programmatic access to the WebApplicationContext. The "contextInitializerClasses" init-param can be passed to the Spring DispatcherServlet, and Spring will call your ACI implementation at the right time, allowing you to manipulate the application context prior to #refresh().
In your case, it appears you are concerned only with activating profiles for an integration test. So your ACI is unnecessary. Mark your integration test with Spring's @ActiveProfiles annotation to dictate which profiles are active.
Note that if spring.profiles.active has been set as a JVM system property or environment variable, the specified profile(s) will be activated automatically. i.e. there is no need to call System#getProperty as you do in your ACI implementation. One thing to note, however, is that based on the logic in your ACI implementation, it appears you want to fall back to a profile named "local" if spring.profiles.active is note supplied as a system property or environment variable. You may be interested to know that there is a "reserved default profile" named literally "default". This probably has the same semantics you're looking for with your "local" profile. Consider renaming your 'local' profile to 'default'.
Finally, note that there does exist an open improvement request for providing ApplicationContextInitializer support in @ContextConfiguration classes: https://jira.springsource.org/browse/SPR-9011. You might want to put a watch on that. It would, for example, allow you a simple option for programmatically activating 'local' if no other profiles are active.
Upvotes: 5
Reputation: 308733
Try adding the locations of your app context XML to the second annotation:
@ContextConfiguration(locations = {
"classpath:applicationContext.xml"
})
Upvotes: 1