単体テストのためのCDIコンテキスト制御

これまでCDIを使った単体テストについて何回か紹介しましたが、そこでは主にインジェクションの対象を切り替える方法について書いてきました。しかし、CDI(Contexts and Dependency Injection)のインジェクションは、単なるインジェクションではなく、インジェクトされるBeanはコンテキストが管理しているのが特徴です。CDIでは、コンテキストの寿命が尽きれば、それにバインドしたBeanも解放されます。そこで、テストケースとしてコンテキストの開始・停止をすることでBeanのライフサイクルを制御をしたいことがあると思います。今回は、DeltaSpikeのCDITestRunnerを使ったときのコンテキストの制御について紹介します。

ContextControl

CDITestRunnerを使ったテストコードでは、ContextControlを使ってApplication/Session/Requestのスコープを制御することができます。

@Inject
private ContextControl contextControl;

ContextControlには以下の機能があります。

  • startContexts()    すべてのコンテキストの開始
  • stopContexts()    すべてのコンテキストの停止
  • startContext(Class<? extends Annotation> scopeClass)  指定されたスコープのコンテキストの開始
  • stopContext(Class<? extends Annotation> scopeClass)  指定されたスコープのコンテキストの停止

ContextControlのサンプルコード

次のサンプルコードは、ApplicationScopeのLoggerとSessionScopeのShoppingCartを題材としてContextControlによるコンテキスト制御をした例になります。

@RunWith(CdiTestRunner.class)
public class ContainerControlTest {
	
	@Inject 
	private Logger logger; // ApplicationScoped

	@Inject
	private ShoppingCart shoppingCart; // SessionScoped

	@Inject
	private ContextControl contextControl;
	
	@Test
	public void testScope() {	
		shoppingCart.put(new Product("001", 1));
		shoppingCart.put(new Product("002", 3));
		shoppingCart.put(new Product("003", 7));
		logger.info("ShoppingCart=>" + shoppingCart);
		contextControl.stopContexts();
		contextControl.startContexts();
		logger.info("ShoppingCart=>" + shoppingCart);
		assertTrue(shoppingCart.isEmpty());
	}
}

CdiTestRunnerでは、テストメソッドtestScope()が呼び出される前に、すべてのコンテキストは自動的に開始されます。この例では、 すべてのコンテキストを明示的に停止するためにcontextControl.stopContexts()を呼び出します。これにより、 ApplicationScopeのLoggerとSessionScopeのShoppingCartはコンテキストから解放されます。次に、続いて contextControl.startContexts()を呼び出すことで、すべてのコンテキストが開始されます。この後ShoppingCart を参照すると、新しいコンテキストにバインドするために新規に生成されますので、その結果として、カートに登録したプロダクトは空に初期化されます。

以下はテスト実行時に出力されたコンソールログの抜粋です。Loggerは@PostConstructでLogger::initialize、@PreDestroyのメソッドでLogger::destroyをコンソールに出力しています。ShoppingCartについても同様にコンソール出力します。コンソール出力を見ると、contextControl.stopContexts()によってShoppingCartとLoggerの両方がdestroyされていることが確認できます。

11 24, 2015 11:35:28 午後 org.apache.deltaspike.testcontrol.api.junit.CdiTestSuiteRunner$LogRunListener testStarted
情報: [run] org.tanoseam.examples.ContainerControlTest#testScope
Logger::initialize
ShoppingCart::initialize
ShoppingCart=>ShoppingCart [products=[Product [productId=001, quantity=1], Product [productId=002, quantity=3], Product [productId=003, quantity=7]]]
ShoppingCart::destroy
Logger::destroy
Logger::initialize
ShoppingCart::initialize
ShoppingCart=>ShoppingCart [products=[]]
11 24, 2015 11:35:28 午後 org.apache.deltaspike.testcontrol.api.junit.CdiTestSuiteRunner$LogRunListener testFinished
情報: [finished] org.tanoseam.examples.ContainerControlTest#testScope
ShoppingCart::destroy
Logger::destroy

上のサンプルコードでは、ApplicationScopeのLoggerも解放してしまっていますが、本来であれば、実際の動きに近づけるためにApplicationScopeのBeanについてはメソッドの先頭で生成し、メソッド終了時に解放したいところです。次の例は、RequestScopeとSessionScopeのコンテキストを個別に制御することで、ApplicationScopeを停止しないようにしています。

	@Test
	public void testScope() {	
		shoppingCart.put(new Product("001", 1));
		shoppingCart.put(new Product("002", 3));
		shoppingCart.put(new Product("003", 7));
		logger.info("ShoppingCart=>" + shoppingCart);
		contextControl.stopContext(RequestScoped.class);
		contextControl.stopContext(SessionScoped.class);
		contextControl.startContext(SessionScoped.class);
		contextControl.startContext(RequestScoped.class);
		logger.info("ShoppingCart=>" + shoppingCart);
		assertTrue(shoppingCart.isEmpty());
	}

以下がこのテストのコンソール出力です。ApplicationScopeのLoggerについて、Logger:initializeが先頭で、Logger.destroyが最後に出力されています。

11 24, 2015 11:40:26 午後 org.apache.deltaspike.testcontrol.api.junit.CdiTestSuiteRunner$LogRunListener testStarted
情報: [run] org.tanoseam.examples.ContainerControlTest#testScope
Logger::initialize
ShoppingCart::initialize
ShoppingCart=>ShoppingCart [products=[Product [productId=001, quantity=1], Product [productId=002, quantity=3], Product [productId=003, quantity=7]]]
ShoppingCart::destroy
ShoppingCart::initialize
ShoppingCart=>ShoppingCart [products=[]]
11 24, 2015 11:40:26 午後 org.apache.deltaspike.testcontrol.api.junit.CdiTestSuiteRunner$LogRunListener testFinished
情報: [finished] org.tanoseam.examples.ContainerControlTest#testScope
ShoppingCart::destroy
Logger::destroy
広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。