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 を反復処理し、それぞれのプロパティをキャッシュしていることに気付きました。(春からのDEBUGメッセージを調べました)

その結果、次のテストの実行には約 14 秒かかります。

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

構成を遅延ロードする方法はありますか? 追加しようとしましdefault-lazy-init="true"たが、うまくいきませんでした。

理想的には、テストに必要な Bean のみがインスタンス化されます。

前もって感謝します。

更新:これは前に述べたはずですが、各テストのコンテキストファイルは必要ありません。また、テスト用の 1 つのコンテキスト ファイルだけでは機能しないと思います。(このテスト コンテキスト ファイルはすべてを含むことになります)

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

1 つのアプローチは、自動検出を完全にスキップし、(テストに必要なコンポーネントを含む) 別のコンテキストをロードするか、実行時に (テストの実行前に) Bean を再定義することです。

このスレッドでは、Bean の再定義と、これを行うためのカスタム テスト クラスについて説明します。

単体テスト環境での Spring Bean の再定義

于 2010-10-04T21:48:06.493 に答える
1

おそらく必要なのは、構成をリファクタリングして自動配線の使用を減らすことです。私のアプローチは、ほとんどの場合、Bean を名前で配線し、設計を明確にしようとしますが、同時に、冗長になりすぎず、マイナーな詳細を隠すために使用していることが明らかな場合は自動配線を使用します。

補遺: それだけでは不十分で、junit を使用している場合は、JUnit Addonsプロジェクトのユーティリティを使用することをお勧めします。このクラスDirectorySuiteBuilderは、ディレクトリ構造からテスト スイートを動的に構築します。だからあなたは次のようなものを作ることができます

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

このコードの前に Spring コンテキストを初期化すると、すべてのテストを一度に実行できます。ただし、各テストが「クリーンな」Spring コンテキストを想定している場合は、おそらく失われます。

于 2010-10-02T17:07:16.543 に答える
1

これは、コンポーネントの自動検出に支払う代償です。遅くなります。テストは特定の Bean のみを必要とします<context:component-scan>が、それははるかに広く、Spring は見つかったすべての Bean をインスタンス化して初期化します。

テストには別の bean ファイルを使用することをお勧めします。これは、テスト自体に必要な Bean のみを定義するもの<context:component-scan>です。

于 2010-09-26T17:12:44.460 に答える
0

従来の Bean ファクトリは、この問題を解決するように設計されており、プロセス全体を 3 倍以上高速化します。

于 2011-10-06T09:03:48.930 に答える
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 に答える