从 Spring Framework 4.2.9 升级到 4.3+ 时自定义 ContextConfiguration Loader 问题

Custom ContextConfiguration Loader issues when upgrading from Spring Framework 4.2.9 to 4.3+

我在 运行 将 Spring 框架 spring 测试依赖项从 4.2.9 升级到 4.3.9 后进行集成测试时遇到一些问题。

我正在使用 ContextConfiguration class,它实现了 spring 测试 SmartContextLoader,它允许我加载不同的 .xml 配置文件,这些文件按配置文件拆分。基于当前的 spring 配置文件,它将 运行 该配置文件的特定 bean。

这个 ContextConfigurationLoader 我 运行 在版本 4.2.9 中完全没问题,但是在升级到版本 4.3 之后,我正在努力解决这个问题。

我包括了我在集成测试中创建的 ContextConfigurationLoader

@ContextConfiguration(loader=ContextConfigurationLoader.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MyIntegrationTest {
     // Test Body
}

ContextConfigurationLoader看起来像这样,

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();
    }
}

最后,这是我在尝试 运行 我的测试后得到的错误响应。

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']]

感谢您的帮助,如果您需要更多信息,请告诉我。

我找到的一个解决方案是将所有 .xml 配置文件包含到一个文件中,并使用这样的 @ContextConfiguration 注释。

@ContextConfiguration("/config.xml")

但这需要对测试之外的其余代码进行一些其他更改。这也无助于解释为什么我当前的实现不适用于最新的 Spring 框架 spring-测试版本。

来自 SmartContextLoader.processContextConfiguration(ContextConfigurationAttributes) 的 Javadoc:

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.

最后一句话中描述的行为是导致您出现问题的原因。

因此,解决您的问题的方法是实际实施 processContextConfiguration() 并在提供的 ContextConfigurationAttributes 中设置一个 bogus 位置。这将指示 Spring 您的自定义加载程序能够正确检测默认值(您在 loadContext() 中硬编码)。然后,您可以从 mergedContextConfiguration.getLocations() 的副本中删除 bogus 位置,然后再将它们传递给 loadBeanDefinitions().

这将使最终用户更干净;然而,另一种方法(如果你除了你自己之外没有任何最终用户)是声明一个现有的 XML 配置文件的位置(通过 @ContextConfiguration),它实际上并没有声明任何豆.

此致,

Sam(Spring TestContext Framework 的作者)