1

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?

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I was hoping to avoid having a base test class which defined all of the configuration options, but it looks like I will not have a choice (currently). I was hoping to avoid having to place which profile was active on each of the test classes (which is easily done here with the JVM property), but I was definitely hoping to avoid having to place the ContextConfiguration annotation on each of my test classes, so moving it up to a base level test will alleviate that problem.
The @ActiveProfiles annotation can be used in a base class and it would apply to all sub-classes. Furthermore, that annotation has a number of properties including one called inheritLocations. See the Javadoc.
1

Try adding the locations of your app context XML to the second annotation:

@ContextConfiguration(locations = {
    "classpath:applicationContext.xml"
})

2 Comments

Will try when i get it on Monday, but there is no xml file currently. Do I add one just todeclare this bean? Seems counter-intuitive when using all java configuration elsewhere.
No, change the annotation so your app context will be loaded on startup.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.