I am having some issues running my integration tests after upgrading the Spring Framework spring-test dependency from 4.2.9 to 4.3.9.
I am using a ContextConfiguration class which implements the spring test SmartContextLoader
which allowed me to load different .xml config files which are split by profile. Based on the current spring profile it will run the specific beans for that profile.
This ContextConfigurationLoader
I have ran perfectly fine in version 4.2.9
but after upgrading to version 4.3
and I am struggling to resolve this issue.
I am including the ContextConfigurationLoader
I created in my integration tests like so.
@ContextConfiguration(loader=ContextConfigurationLoader.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MyIntegrationTest {
// Test Body
}
The ContextConfigurationLoader
looks like this,
public class ContextConfigurationLoader implements SmartContextLoader {
@Override
public void processContextConfiguration(ContextConfigurationAttributes contextConfigurationAttributes) {
}
@Override
public ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) throws Exception {
GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.getEnvironment().setActiveProfiles(mergedContextConfiguration.getActiveProfiles());
new XmlBeanDefinitionReader(context).
loadBeanDefinitions(mergedContextConfiguration.getLocations());
context.load(
"/development.xml",
"/staging.xml",
"/production.xml",
);
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
context.refresh();
context.registerShutdownHook();
return context;
}
@Override
public String[] processLocations(Class<?> aClass, String... strings) {
return new String[0];
}
@Override
public ApplicationContext loadContext(String... strings) throws Exception {
ApplicationContext context = ApplicationContextFactory.create();
context.getBean("dbUnitDatabaseConnection");
return ApplicationContextFactory.create();
}
}
Lastly this is the error response I get after attempting to run my tests.
java.lang.IllegalStateException: ContextConfigurationLoader was unable to detect defaults, and no ApplicationContextInitializers or ContextCustomizers were declared for context configuration attributes [[ContextConfigurationAttributes@53ca01a2 declaringClass = 'com.class.path.to.MyIntegrationTest', classes = '{}', locations = '{}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'com.class.path.to.ContextConfigurationLoader']]
Thanks for your help, let me know if you need anymore information.
One solution I have found is including all of the .xml config files into one file and using the @ContextConfiguration
annotation like this.
@ContextConfiguration("/config.xml")
But this would require some other changes to the rest of the code outside of the tests. This also doesn't help explain why my current implementation doesn't work on the latest Spring Framework spring-test version.
From the Javadoc of SmartContextLoader.processContextConfiguration(ContextConfigurationAttributes)
:
Note: in contrast to a standard ContextLoader, a SmartContextLoader must preemptively verify that a generated or detected default actually exists before setting the corresponding locations or classes property in the supplied ContextConfigurationAttributes. Consequently, leaving the locations or classes property empty signals that this SmartContextLoader was not able to generate or detect defaults.
The behavior described in the last sentence is what is causing you problems.
Thus, a solution to your problem would be to actually implement processContextConfiguration()
and set a bogus location in the supplied ContextConfigurationAttributes
. That would instruct Spring that your custom loader was able to properly detect defaults (which you hard code in loadContext()
). You could then remove the bogus location from a copy of mergedContextConfiguration.getLocations()
before passing them to loadBeanDefinitions()
.
That would make it cleaner for end users; however, an alternative (if you don't really have any end users other than yourself) would be to declare the location of an existing XML configuration file (via @ContextConfiguration
) that simply does not actually declare any beans.
Regards,
Sam (author of the Spring TestContext Framework)