2016-03-30 76 views
5

@ComponentScanのテストでは、@ComponentScanの問題が発生しました。つまり、@ComponentScanが統合テスト中に意図せずに引き込まれています。例えば@ComponentScanのテストクラスの設定を除外

com.example.config.GlobalConfiguration、あなたがcom.example.service内のコンポーネントに引っ張るsrc/main/javaでいくつかのグローバル設定を持っていると言う:

package com.example.config; 
... 
@Configuration 
@ComponentScan(basePackageClasses = ServiceA.class) 
public class GlobalConfiguration { 
    ... 
} 

2つのサービス、com.example.services.ServiceAcom.example.services.ServiceBに引っ張るためのものだ、@Component@Profile("!test")で注釈を付け(簡略化のため省略されている)。 SRC /テスト/ javaの、com.example.services.ServiceATestで次に

package com.example.services; 
... 
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = ServiceATest.ServiceATestConfiguration.class) 
public class ServiceATest { 
    ... 
    @Configuration 
    public static class ServiceATestConfiguration { 
     @Bean 
     public ServiceA serviceA() { 
      return ServiceA(somemocking...); 
     } 
    } 
} 

com.example.ServiceBIntegrationTest、統合テストであるためにGlobalConfiguration.classにプルする必要がありますが、それでも@ActiveProfiles("test")と危険な実装で引っ張って回避:

package com.example.services; 
... 
@RunWith(SpringJUnit4ClassRunner.class) 
@ActiveProfiles("test") 
@ContextConfiguration(classes = {GlobalConfiguration.class, ServiceBIntegrationTest.ServiceBIntegrationTestConfiguration.class}) 
public class ServiceBIntegrationTest { 
    ... 
    @Configuration 
    public static class ServiceBIntegrationTestConfiguration { 
     @Bean 
     public ServiceB serviceB() { 
      return ServiceB(somemocking...); 
     } 
    } 
} 

ServiceBIntegrationTestの明白な意図は、危険な除外GlobalConfigurationを経由して、完全なsrc/main/javaアプリケーション構成で引っ張っていますコンポーネントを@ActiveProfiles("test")経由で削除し、除外されたコンポーネントを独自の実装に置き換えます。しかし、テスト中にsrc/main/javasrc/test/javaという名前空間が組み合わされているため、GlobalConfiguration@ComponentScanは、通常よりもクラスパスのほうが多く、つまり、ServiceA.ServiceATestConfigurationで定義されたServiceAのBeanを検出します。それは容易に矛盾や意図しない結果につながる可能性があります。

GlobalConfigurationのようなものを@ComponentScan(..., excludeFilters= @ComponentScan.Filter(type = FilterType.REGEX, pattern = "\\.*(T|t)est\\.*"))とすることもできますが、それ自体に問題があります。命名規則に頼っているのはかなり脆弱です。たとえあなたが@TestConfiguration注釈を無効にしてFilterType.ANNOTATIONを使用したとしても、をご存知であれば、あなたのsrc/test/javaを認識させることになります。注:下記のを参照してください。

私の問題は、追加プロファイルを使用して解決しました。 ServiceAに、固有のプロファイル名を追加します。そのプロファイルの注釈は@ActiveProfiles("test,serviceatest")のようになります。次に、ServiceATest.ServiceATestConfigurationに、@Profile("serviceatest")の注釈を追加します。これは、効果的に比較的少ないオーバーヘッドでServiceATestConfigurationの範囲を制限しますが、それは次のようにどちらかのようだ:私は間違って@ComponentScanを使用していますa)の

、または

b)は、この問題

を処理するための非常にクリーンパターンがあるはずです

どちらですか?


ノート:はい、それは@Profile("!test")を使用していますので、アプリがテスト認識しているが、私は不適切なリソースの使用状況から身を守るために少しテスト対応のアプリケーションを作成して確保することがテストを意識した作りと主張したいですテストの正確さは非常に異なるものです。

答えて

1

私は統合テスト中にSpring Beanを偽造しようとしています。@Profile@ActiveProfilesの注釈を@Primary注釈と組み合わせると、ほとんどの頭痛が消えて、生産豆に@Profile("!test")とマークする必要はありません。

blog post on the topicGithub examplesと書きました。

コメントに対する反応:

パッケージ構造によって。コンポーネントスキャンは、現在のパッケージとサブパッケージ内のすべてのパッケージをスキャンします。 Beanをスキャンしたくない場合は、Beanがコンポーネントスキャンの傘の下にないようにパッケージ構造を修正してください。

春は、パッケージをsrc/test/javaまたはsrc/main/javaから区別しません。 @Profile("!test")の生産豆を排除しようとするとデザインの匂いがする。あなたはそれを避けるべきです。私は上記のブログからアプローチする機会を与えることを提案します。

@Primaryアノテーションを使用してBeanをオーバーライドするときは、@DirtiesContext注釈を使用して他のテストでクリーンシートを作成する必要があることに注意してください。

+1

ええ、そのパターンにはいくつかの利点がありますが、それは私の質問についてではありません。私は、コンポーネントスキャンパッケージ内の構成の範囲を最大限に制限する方法を求めています。 – jwilner

+1

パッケージを変更すると、パッケージのローカルスコープと競合する可能性があります。これはテストでは明らかに重要です。これは不満足です。 – jwilner

関連する問題