ArquillianでJavaEEテスト(CDI・interceptor)

#概要
JavaEEのテストをJavaEEのテスティングフレームワークであるArquillianで実施してみます。
CDIとinterceptorがJavaEEサーバを用意せずともローカルで動かすことができるので、便利です。

今回使用したソースはGithubにUPしています。
https://github.com/tuto00/Arquillian

#対象読者
JavaEEのテスト初心者

#準備
##Maven
Mavenを使用するため、pom.xmlを編集します。
JavaEE、Junit、Arquillianのライブラリの依存関係を追加します。

```:pom.xml
	<dependencies>
		<dependency>
			<groupId>org.jboss.spec</groupId>
			<artifactId>jboss-javaee-7.0</artifactId>
			<version>1.0.3.Final</version>
			<type>pom</type>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.arquillian</groupId>
			<artifactId>arquillian-bom</artifactId>
			<version>1.4.0.Final</version>
			<scope>import</scope>
			<type>pom</type>
		</dependency>
		<dependency>
			<groupId>org.jboss.arquillian.junit</groupId>
			<artifactId>arquillian-junit-container</artifactId>
			<version>1.4.0.Final</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.arquillian.container</groupId>
			<artifactId>arquillian-weld-ee-embedded-1.1</artifactId>
			<version>1.0.0.CR9</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.weld</groupId>
			<artifactId>weld-core</artifactId>
			<version>2.3.5.Final</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-simple</artifactId>
			<version>1.6.4</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
```

##beans.xml
interceptorを使用したいため用意してください。

```:beans.xml
<?xml version="1.0" ?>
<beans
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
    version="1.1"
    bean-discovery-mode="all">

     <interceptors>
        <class>org.arquillian.interceptor.TraceInterceptor</class>
    </interceptors>

</beans>
```

#実装
GreetServiceクラスにHelloクラスをInjectします。
また、GreetServiceクラスにInterceptor(SampleInterceptor)を適用し、メソッド実行前後でログ出力を行います。

```java:GreetService.java
@Named
@ApplicationScoped
@SampleInterceptor
public class GreetService {

	@Inject
	Hello hello;

    public String greet(){
    	return hello.hello();
    }
}
```
　
Helloクラスにも@ApplicationScopedを付与してCDI管理Beanにしています。

```java:Hello.java
@ApplicationScoped
public class Hello {

	public String hello() {
		return "helloWorld";
	}
}
```

次に、Interceptorを特定し、実行するためのアノテーションを作成します。

```java:SampleInterceptor.java
@Inherited
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface SampleInterceptor {
}
```

そして、上記で作成したSampleInterceptorを実装する形で以下を準備します。
メソッド実行前にクラス名、メソッド名を出力するようにしています。

```java:TraceInterceptor.java
@Interceptor
@SampleInterceptor
public class TestInterceptor {
	@AroundInvoke
	public Object obj(InvocationContext ic) throws Exception {

		// メソッド実行前
		System.out.println("process start class :" + ic.getTarget().getClass().getSimpleName()
				+ " method:" + ic.getMethod().getName());

		// メソッド実行
		Object result = ic.proceed();

		// メソッドの実行後
		System.out.println("process end");

		return result;
	}
}
```

#テストコード
やっと本題のArquillianを使用します。
テストコードを書いていきます。

```java:GreetServiceTest.java
@RunWith(Arquillian.class)
public class GreetServiceTest {

	@Inject
	GreetService greeter;

	@Deployment
	public static JavaArchive createDeployment() {
		JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
				.addPackage("org.arquillian.example")
				.addPackage("org.arquillian.annotation")
				.addPackage("org.arquillian.interceptor")
				.addAsManifestResource(new File("src/main/webapp/WEB-INF/beans.xml"));
		System.out.println(jar.toString(true));
		return jar;
	}

	@Test
	public void should_create_greeting() {
		assertEquals("helloWorld", greeter.greet());
	}
}
```

通常のJunitとは異なりArquillianを使用するときのポイントは２つあります。
* テストクラスに@RunWith(Arquillian.class)を付与します。
* @Deploymentを付与したアーカイブ作成メソッドを作成します。

動きとしては以下となります。
>@RunWith アノテーションは、JUnitに、Arquillianをテストコントローラとして使用することを伝えます。Arquillianはテストアーカイブ（つまり、マイクロデプロイメント）を受け取るために @Deployment アノテーションのついたパブリックなスタティックメソッドを探します。そしてマジックが起きて、それぞれの @Test メソッドはコンテナ環境内で実行されます。

要は、jarを作成して、コンテナで実行しているということですね。
コンテナについては、Arquillianのコンテナアダプタがコントロールしています。
今回はコンテナとしてWeldを使用し、コンテナアダプタとしてarquillian-weld-ee-embedded-1.1を使用しています。

#テスト実行
さあ、テストを実行してみましょう。
通常のJunitと同じく、テストクラスをJunit実行すればよいです。

テスト結果がグリーンになり、コンソールに以下が出力していることを確認してください。

```
588b9820-a6f0-4ffe-b6bd-e8228bc24b98.jar:
/org/
/org/arquillian/
/org/arquillian/example/
/org/arquillian/example/Hello.class
/org/arquillian/example/GreetService.class
/org/arquillian/example/GreeterTest.class
/org/arquillian/annotation/
/org/arquillian/annotation/SampleInterceptor.class
/org/arquillian/interceptor/
/org/arquillian/interceptor/TraceInterceptor.class
/META-INF/
/META-INF/beans.xml
INFO: WELD-000900: 2.3.5 (Final) [日 6 23 18:06:32 JST 2019]
process start class :GreetService$Proxy$_$$_WeldSubclass method:greet
process end
```
process start、process endとinterceptorが適用されていることがわかります。


#おわりに
Arquillianを使用すると、CDIやintercptorを簡単にテストすることができます。
みなさんも使ってみてください。

難点としては、ドキュメントが少ないことです。。。

#参考URL
[Arquillian Guides](http://arquillian.org/guides/getting_started_ja/)