2

We have a spring application that runs in one of a few ways, depending on a specific property, which has to be one of a small set of values. When the application starts up, this property gets passed to a factory, which then builds slightly different bean implementations depending on it.

I'd like to write an integration test for the functionality this controls to ensure it works when the property is set to various values; so it needs to run one test with the property set to 1, one test with the property set to 2, etc. Each test needs to set the property as required, and then reload the configuration so that everything is reconfigured correctly.

Getting the context and manually refreshing it in each test seems simple enough, but how can I inject these different properties in the tests at runtime to control this? Is there any better way of organising this sort of configuration?

3
  • Take a look at Arquillian (jboss.org/arquillian.html) - it allows to package any desirable subset of application files into test archive - you can publish different property files for different tests Commented Jan 11, 2013 at 11:08
  • Is this property so far reaching that it affects the entire service? Can't the functional perimeter be reduced to something that you can mock? Commented Jan 11, 2013 at 11:11
  • @fge The parameter affects what gets injected into quite a few other beans across the system, when the system is initialised (once for the whole suite at the moment), so not really. Commented Jan 11, 2013 at 11:15

3 Answers 3

1

I am going to answer to your second question...so, is there any better way of organising this sort of configuration? It may be overwhelming for your case, but did you give a look to Spring Profiles? It does what you need and it is a new feature introduced in Spring 3.1, so it seems the way to go the Spring team chose for this kind of problems.

Here a great tutorial: http://blog.springsource.org/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles/

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

2 Comments

Is there any way to do this pre-3.1? We're on 3.0.5 and upgrading to 3.1 breaks things currently. I spend a few days fixing that, if it's the only way, but I'd rather not if I don't have to...
No, Spring Profiles have been introduced in the 3.1 release. Either you upgrade or you stick with previous solutions like the one from @Jayamohan. I am not expert on this, but give a look to Maven Profiles (if you are using Maven of course)
1

I eventually found a way to actually do this directly. It's slightly messy, but not actually too bad.

Originally, the tests were being run with an @ContextConfiguration, and then later initialised with new TestContextManager(getClass()).prepareTestInstance(this); in the @Before (initialised separately so we could use runners other than the Spring one).

I extended this to first register a text execution listener which just grabbed the TestContext into the test itself whenever one became available:

contextManager.registerTestExecutionListeners(new AbstractTestExecutionListener() {
    @Override
    public void prepareTestInstance(TestContext freshTestContext) throws Exception {
        testContext = freshTestContext;
    }
});

The test itself then injects a property into a custom PropertyPlaceholderConfigurer (extremely simple: overrides resolvePlaceholder, calls super.resolvePlaceholder unless you've previously explicitly set the property) once it knows what the property's actual value is (not until the actual test, unfortunately), and calls:

testContext.markApplicationContextDirty();
contextManager.prepareTestInstance(this);

which makes the TestContext rebuild the application context, now using the newly changed property value.

Finally, you then need to remember to reset the property between tests, and probably mark the whole class as @DirtiesContext, to stop it interfering with your other tests.

Comments

0

Consider using a JVM System property that sets the environment (e.g. “my.env=sit”), telling the configurer which property file to use. For example:

<context:property-placeholder   
    location="classpath:db-${my.env}.properties"/>

If the “my.env” property was set to “sit”, then obviously the PropertyPlacementConfigurer would look for a file called “db-sit.properties".

Dont forget to set ignoreUnresolvablePlaceholders to true. Which will ensure that a configurer won’t fail if it can’t find a property.

Comments

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.