19

我正在尝试加快我们环境中的集成测试。我们所有的课程都是自动装配的。在我们的 applicationContext.xml 文件中,我们定义了以下内容:

<context:annotation-config/>
<context:component-scan base-package="com.mycompany.framework"/>
<context:component-scan base-package="com.mycompany.service"/>
...additional directories

我注意到 Spring 正在扫描上面指出的所有目录,然后遍历每个 bean 并缓存每个 bean 的属性。(我回顾了春天的 DEBUG 消息)

因此,以下测试需要大约 14 秒才能运行:

public class MyTest extends BaseSpringTest {
  @Test
  def void myTest(){
    println "test"
  }
}

有没有办法延迟加载配置?我尝试添加default-lazy-init="true",但没有奏效。

理想情况下,仅实例化测试所需的 bean。

提前致谢。

更新:我之前应该说过,我不想为每个测试都有一个上下文文件。我也不认为仅用于测试的上下文文件会起作用。(这个测试上下文文件最终会包含所有内容)

4

7 回答 7

16

如果您真的想加快应用程序上下文,请禁用 <component-scan 并在运行任何测试之前执行以下例程

Resource resource = new ClassPathResource(<PUT_XML_PATH_RIGHT_HERE>); // source.xml, for instance
InputStream in = resource.getInputStream();

Document document = new SAXReader().read(in);
Element root  = document.getRootElement();

/**
  * remove component-scanning
  */
for ( Iterator i = root.elementIterator(); i.hasNext(); ) {
    Element element = (Element) i.next();

    if(element.getNamespacePrefix().equals("context") && element.getName().equals("component-scan"))
        root.remove(element);
}

in.close();

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(true);
for (String source: new String[] {"com.mycompany.framework", "com.mycompany.service"}) {
    for (BeanDefinition bd: scanner.findCandidateComponents(source)) {
        root
        .addElement("bean")
        .addAttribute("class", bd.getBeanClassName());
    }
}

//add attribute default-lazy-init = true
root.addAttribute("default-lazy-init","true");

/**
  * creates a new xml file which will be used for testing
  */ 
XMLWriter output = new XMLWriter(new FileWriter(<SET_UP_DESTINATION_RIGHT_HERE>));
output.write(document);
output.close(); 

除此之外,启用 <context:annotation-config/>

由于您需要在运行任何测试之前执行上述例程,您可以创建一个抽象类,您可以在其中运行以下命令

为测试环境设置 Java 系统属性如下

-Doptimized-application-context=false

public abstract class Initializer {

    @BeforeClass
    public static void setUpOptimizedApplicationContextFile() {
        if(System.getProperty("optimized-application-context").equals("false")) {
            // do as shown above

            // and

            System.setProperty("optimized-application-context", "true"); 
        }

    }

}

现在,对于每个测试类,只需扩展 Initializer

于 2010-10-05T07:30:00.697 回答
2

一种方法是完全跳过自动检测并加载单独的上下文(包含测试所需的组件)或在运行时重新定义您的 bean(在测试运行之前)。

该线程讨论了 bean 的重新定义和用于执行此操作的自定义测试类:

单元测试环境中的Spring bean重新定义

于 2010-10-04T21:48:06.493 回答
1

这是您为自动检测组件所付出的代价——速度较慢。尽管您的测试只需要某些 bean,但您的测试<context:component-scan>范围更广,Spring 将实例化并初始化它找到的每个 bean。

我建议您为测试使用不同的 beans 文件,该文件仅定义测试本身所需的 beans,即不使用<context:component-scan>.

于 2010-09-26T17:12:44.460 回答
1

可能您需要的是重构您的配置以使用更少的自动装配。我的方法几乎总是按名称连接 bean,试图明确设计,但同时也不要太冗长,在明确使用自动连接时使用它以隐藏次要细节。

附录: 如果这还不够,并且您正在使用 junit,您可能需要使用JUnit Addons项目中的实用程序。该类DirectorySuiteBuilder从目录结构动态构建测试套件。所以你可以制作类似的东西

DirectorySuiteBuilder builder = new DirectorySuiteBuilder();
Test suite = builder.suite("project/tests");

在此代码之前初始化 Spring 上下文,您可以一次运行所有测试。但是,如果每个测试都假设一个“干净”的 Spring 上下文,那么您可能会迷路。

于 2010-10-02T17:07:16.543 回答
0

Convention bean factory旨在解决这个问题并显着加快整个过程,3 倍或更多。

于 2011-10-06T09:03:48.930 回答
0

在这种情况下,你需要找到一个平衡点。一方面,您理所当然地希望在尽可能短的时间内运行测试以快速获得结果。在具有持续集成工作的团队环境中工作时,这一点尤其重要。另一方面,您也理所当然地希望保持测试的配置尽可能简单,这样测试套件的维护就不会变得太麻烦而无用。

但归根结底,您需要找到自己的平衡点并做出决定。我建议创建一些用于测试的上下文配置文件来对一些测试进行分组,这样一个简单的测试不会花费很长时间,只需由 Spring 配置即可,同时将配置文件的数量保持在您可以管理的最低限度。

于 2010-10-04T23:38:20.910 回答
0

由于这里的答案都没有为我解决这个问题,我添加了我自己的经验。

我的问题是 Spring、Hibernate 和 EhCache 组合在一起试图用冗长的DEBUG消息淹没我的控制台,从而导致无法读取的日志以及 - 更糟糕的是 - 无法忍受的低性能。

配置他们的日志级别全部修复:

Logger.getLogger("org.hibernate").setLevel(Level.INFO);
Logger.getLogger("net.sf.ehcache").setLevel(Level.INFO);
Logger.getLogger("org.springframework").setLevel(Level.INFO);
于 2011-12-26T08:11:21.177 回答