コンテキストキャッシング

TestContext フレームワークがテスト用に ApplicationContext (または WebApplicationContext)をロードすると、そのコンテキストはキャッシュされ、同じテストスイート内で同じ一意のコンテキスト構成を宣言する後続のすべてのテストで再利用されます。キャッシングの仕組みを理解するには、「一意」と「テストスイート」の意味を理解することが重要です。

ApplicationContext は、ロードに使用される構成パラメーターの組み合わせによって一意に識別できます。構成パラメーターの一意の組み合わせを使用して、コンテキストがキャッシュされるキーを生成します。TestContext フレームワークは、次の構成パラメーターを使用してコンテキストキャッシュキーを構築します。

  • locations (@ContextConfiguration から)

  • classes (@ContextConfiguration から)

  • contextInitializerClasses (@ContextConfiguration から)

  • contextCustomizers (ContextCustomizerFactory から)–これには、@DynamicPropertySource メソッド、@MockBean や @SpyBean などの Spring Boot のテストサポートからのさまざまな機能が含まれます。

  • contextLoader (@ContextConfiguration から)

  • parent (@ContextHierarchy から)

  • activeProfiles (@ActiveProfiles から)

  • propertySourceDescriptors (@TestPropertySource から)

  • propertySourceProperties (@TestPropertySource から)

  • resourceBasePath (@WebAppConfiguration から)

例: TestClassA が @ContextConfiguration の locations (または value)属性に {"app-config.xml", "test-config.xml"} を指定する場合、TestContext フレームワークは対応する ApplicationContext をロードし、それらのロケーションのみに基づくキーの static コンテキストキャッシュに格納します。そのため、TestClassB がその場所の {"app-config.xml", "test-config.xml"} も(継承を介して明示的または暗黙的に)定義し、@WebAppConfiguration、異なる ContextLoader、異なるアクティブプロファイル、異なるコンテキスト初期化子、異なるテストプロパティソース、異なる親コンテキストを定義しない場合、同じ ApplicationContext は両方のテストクラスで共有されます。これは、アプリケーションコンテキストを読み込むためのセットアップコストが 1 回(テストスイートごとに)発生するだけであり、その後のテスト実行がはるかに高速であることを意味します。

テストスイートと分岐プロセス

Spring TestContext フレームワークは、アプリケーションコンテキストを静的キャッシュに格納します。これは、コンテキストが文字通り static 変数に格納されることを意味します。つまり、テストが別々のプロセスで実行される場合、静的キャッシュは各テスト実行の間にクリアされ、キャッシュメカニズムを効果的に無効にします。

キャッシングメカニズムを活用するには、すべてのテストを同じプロセスまたはテストスイート内で実行する必要があります。これは、IDE 内のグループとしてすべてのテストを実行することで実現できます。同様に、Ant、MavenGradle などのビルドフレームワークでテストを実行する場合、ビルドフレームワークがテスト間で分岐しないことを確認することが重要です。例: Maven Surefire プラグインの forkMode [Apache] (英語) が always または pertest に設定されている場合、TestContext フレームワークはテストクラス間のアプリケーションコンテキストをキャッシュできず、結果としてビルドプロセスの実行が大幅に遅くなります。

コンテキストキャッシュのサイズは、デフォルトの最大サイズ 32 に制限されています。最大サイズに達すると、最も最近使用されていない(LRU)エビクションポリシーを使用して、古いコンテキストをエグジットして閉じます。spring.test.context.cache.maxSize という名前の JVM システムプロパティを設定することにより、コマンドラインまたはビルドスクリプトから最大サイズを構成できます。別の方法として、SpringProperties メカニズムを介して同じプロパティを設定できます。

特定のテストスイート内に多数のアプリケーションコンテキストをロードすると、スイートの実行に不必要に長い時間がかかる可能性があるため、ロードおよびキャッシュされたコンテキストの数を正確に把握することはしばしば有益です。基盤となるコンテキストキャッシュの統計を表示するには、org.springframework.test.context.cache ロギングカテゴリのログレベルを DEBUG に設定できます。

万が一、テストによってアプリケーションコンテキストが破損し、リロードが必要になった場合(たとえば、Bean 定義またはアプリケーションオブジェクトの状態を変更することにより)、テストクラスまたはテストメソッドに @DirtiesContext アノテーションを付けることができます(の @DirtiesContext の説明を参照)。Spring Test アノテーション)。これは、同じアプリケーションコンテキストを必要とする次のテストを実行する前に、キャッシュからコンテキストを削除してアプリケーションコンテキストを再構築するように Spring に指示します。@DirtiesContext アノテーションのサポートは、デフォルトで有効になっている DirtiesContextBeforeModesTestExecutionListener および DirtiesContextTestExecutionListener によって提供されることに注意してください。

ApplicationContext のライフサイクルとコンソールログ

Spring TestContext フレームワークで実行されたテストをデバッグする必要がある場合は、コンソール出力(つまり、SYSOUT および SYSERR ストリームへの出力)を分析すると便利です。一部のビルドツールと IDE は、コンソール出力を特定のテストに関連付けることができます。ただし、一部のコンソール出力は、特定のテストに簡単に関連付けることができません。

Spring Framework 自体または ApplicationContext に登録されたコンポーネントによってトリガーされるコンソールロギングに関しては、テストスイート内で Spring TestContext フレームワークによってロードされた ApplicationContext のライフサイクルを理解することが重要です。

テストの ApplicationContext は通常、テストクラスのインスタンスが準備されているときにロードされます。たとえば、テストインスタンスの @Autowired フィールドへの依存性注入を実行します。これは、ApplicationContext の初期化中にトリガーされたコンソールログは、通常、個々のテストメソッドに関連付けることができないことを意味します。ただし、@DirtiesContext セマンティクスに従ってテストメソッドを実行する直前にコンテキストが閉じられている場合、コンテキストの新しいインスタンスは、テストメソッドの実行の直前にロードされます。後者のシナリオでは、IDE またはビルドツールがコンソールログを個々のテストメソッドに関連付ける可能性があります。

テスト用の ApplicationContext は、次のいずれかのシナリオで閉じることができます。

  • コンテキストは、@DirtiesContext セマンティクスに従って閉じられます。

  • LRU エビクションポリシーに従ってキャッシュから自動的にエビクトされたため、コンテキストは閉じられます。

  • テストスイートの JVM が終了すると、JVM シャットダウンフックを介してコンテキストが閉じられます。

特定のテストメソッドの後に @DirtiesContext セマンティクスに従ってコンテキストが閉じられた場合、IDE またはビルドツールは、コンソールログを個々のテストメソッドに関連付ける可能性があります。テストクラスの後に @DirtiesContext セマンティクスに従ってコンテキストが閉じられた場合、ApplicationContext のシャットダウン中にトリガーされたコンソールログを個々のテストメソッドに関連付けることはできません。同様に、JVM シャットダウンフックを介してシャットダウンフェーズ中にトリガーされたコンソールログは、個々のテストメソッドに関連付けることはできません。

Spring ApplicationContext が JVM シャットダウンフックを介して閉じられると、シャットダウンフェーズ中に実行されるコールバックは、SpringContextShutdownHook という名前のスレッドで実行されます。JVM シャットダウンフックを介して ApplicationContext が閉じられたときにトリガーされるコンソールログを無効にする場合は、そのスレッドによって開始されたログを無視できるカスタムフィルターをログフレームワークに登録できる場合があります。