自动装配时,Spring集成测试速度很慢

时间:2010-09-20 22:55:54

标签: java unit-testing spring autowired

我正在尝试加速环境中的集成测试。我们所有的课程都是自动装配的。在我们的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。

提前感谢。

更新:我之前应该说过,我不想为每个测试都有一个上下文文件。我也不认为只有测试的一个上下文文件才有效。 (此测试上下文文件最终将包含所有内容)

7 个答案:

答案 0 :(得分:15)

如果您真的想加快应用程序上下文,请停用&lt;组件扫描并执行以下例程,然后再运行任何测试

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

除此之外,启用&lt; context:annotation-config /&gt;

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

设置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

答案 1 :(得分:2)

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

此主题讨论bean的重新定义以及用于执行此操作的自定义测试类:

Spring beans redefinition in unit test environment

答案 2 :(得分:1)

这是您为组件自动检测所支付的价格 - 它的速度较慢。即使你的测试只需要某些bean,你的<context:component-scan>要广泛得多,Spring会实例化并初始化它找到的每个bean。

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

答案 3 :(得分:1)

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

<强>附录: 如果这还不够并且您使用的是junit,则可能需要使用JUnit Addons项目中的实用程序。类DirectorySuiteBuilder从目录结构动态构建测试套件。所以你可以做类似

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

在此代码之前初始化Spring上下文,您可以立即运行所有测试。但是,如果每个测试都采用“干净”的Spring上下文,那么您可能会丢失。

答案 4 :(得分:0)

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

但是在一天结束时,您需要找到自己的平衡并做出决定。 我建议创建一些上下文配置文件进行测试,以便对一些测试进行分组,这样一个简单的测试不需要花费很长时间就可以简单地由Spring配置,同时保持配置文件的数量最少,你可以管理。

答案 5 :(得分:0)

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

答案 6 :(得分: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);