Arquillian + AS7を見てみる

http://design.jboss.org/jbossAS/logo/final/jbossas7_logo_450px.png

7月12日に、JBoss Application Server 7 (AS7) がリリースされた*1。機能面の紹介は本家のページこちらに譲るとして、リリース当初から結合テストフレームワークである、Arquillianをサポートしているところに注目したい。
ということで、この記事ではAS7とArquillianでどのようにテストを行うかを見ていく。

http://design.jboss.org/arquillian/logo/final/arquillian_logo_200px.png


これまで、JavaEEコンポーネントJUnitなどテスティングフレームワークで統合テストをするのはなかなか難しかった。DIが普及しているし、JavaEE5からはPOJOを利用できるようになったので、単体テストはずっと容易になったけれども、実際にデプロイしてみないとテストできないこともたくさんあり、これについてはいろんな人がさまざまな試みをしてきている。

xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series (Fowler))

xUnit Test Patterns: Refactoring Test Code (Addison-Wesley Signature Series (Fowler))

Test Driven: TDD and Acceptance TDD for Java Developers

Test Driven: TDD and Acceptance TDD for Java Developers

さて、Arquillianを利用すると、JUnitTestNGのテストケース内で、ずっと容易にコンテナを利用したテストを行うことができる。コンテナの利用方法は3種類あって、

  • remote
    • 起動している外部のコンテナを利用してテスト。当然、コンテナは、テストケースのJVMとは別のJVMで起動している。
  • managed
    • 外部のコンテナの起動〜停止の管理も含めてテスト。コンテナは、テストケースのJVMとは別JVMとして起動。
  • embedded
    • 内部のコンテナを利用してテスト。コンテナとテストケースのJVMは同一。


対応済みのコンテナは、こちらにあるようにJBoss AS5〜7、GlassFish 3.1、Weld SE 1.0、1.1など。また、GitHubには、OpenShiftWebSphereSpringコンテナ用のプロジェクトも、一応存在している。一応。


自分でコードを書いて試したいところだが、まずは、ドキュメントで紹介されている、サンプルコードを見てみる。まずは、ASダウンロードのページから、"Quick Starts"をダウンロードする。ダウンロードしたjboss-as-quickstarts-7.0.0.Final-dist.zipを展開すると、以下のようにプロジェクトがいくつかある。

jboss-as-quickstarts-7.0.0.Final% ls -F
helloworld/  helloworld-osgi/  kitchensink/  login/  numberguess/  pom.xml  README.md

Arquillianのサンプルは、kitchensinkにある。


以下の内容は、Arquillianのドキュメント Chapter 3. Getting started*2と、kitchensinkを元にしている。また今回は、pom.xmlとテストコードのみさらっと見てみる。


kitchensink/pom.xml
まずJUnitを利用するArquillianを設定している。バージョンは1.0.0.CR1*3

<dependency>
   <groupId>org.jboss.arquillian.junit</groupId>
   <artifactId>arquillian-junit-container</artifactId>
   <version>1.0.0.CR1</version>
   <scope>test</scope>
</dependency>

テスト時に利用するAPIdependencyとして指定している。

<dependency>
   <groupId>org.jboss.spec</groupId>
   <artifactId>jboss-javaee-web-6.0</artifactId>
   <version>2.0.0.Final</version>
   <type>pom</type>
   <scope>provided</scope>
</dependency>

前述のようにJUnitを利用する。

<dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>4.8.1</version>
   <scope>test</scope>
</dependency>

テスト環境をprofileとして指定。これはmanaged設定。

<profile>
   <!-- An optional Arquillian testing profile that executes tests 
      in your JBoss AS instance -->
   <!-- This profile will start a new JBoss AS instance, and execute the
        test, shutting it down when done -->
   <!-- Run with: mvn clean test -Parq-jbossas-managed -->
   <id>arq-jbossas-managed</id>
   <dependencies>
      <dependency>
         <groupId>org.jboss.as</groupId>
         <artifactId>jboss-as-arquillian-container-managed</artifactId>
         <version>7.0.0.CR1</version>
         <scope>test</scope>
      </dependency>
   </dependencies>
</profile>

おなじくテスト環境をprofileとして指定。これはremote設定。

<profile>
   <!-- An optional Arquillian testing profile that executes tests 
      in a remote JBoss AS instance -->
   <!-- Run with: mvn clean test -Parq-jbossas-remote -->
   <id>arq-jbossas-remote</id>
   <dependencies>
      <dependency>
         <groupId>org.jboss.as</groupId>
         <artifactId>jboss-as-arquillian-container-remote</artifactId>
         <version>7.0.0.CR1</version>
         <scope>test</scope>
      </dependency>
   </dependencies>
</profile>

kitchensink/src/test/resources/arquillian.xml
arquillian.xmlにはテスト環境に依存する設定を記述する。例えばJBossの配置場所。

<container qualifier="jboss" default="true">
   <protocol type="jmx-as7">
      <property name="executionType">REMOTE</property>
   </protocol>
   <configuration>
      <property name="jbossHome">/path/to/jboss/as</property>
   </configuration>
</container>

kitchensink/src/test/java/org/jboss/as/quickstarts/kitchensink/test/MemberRegistrationTest.java
最後にテストコード。

  • @RunWithアノテーションで、Arquillianクラスを指定
  • @Deploymentのついたメソッドで、テスト対象のクラスをWARファイルとしてまとめてコンテナにデプロイ
  • @Injectを利用可能。
  • @Testのついたメソッドで、テスト実行
@RunWith(Arquillian.class)
public class MemberRegistrationTest {
   @Deployment
   public static Archive<?> createTestArchive() {
      return ShrinkWrap.create(WebArchive.class, "test.war")
            .addClasses(Member.class, MemberRegistration.class, Resources.class)
            .addAsResource("META-INF/persistence.xml", "META-INF/persistence.xml")
            .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
   }

   @Inject
   MemberRegistration memberRegistration;

   @Inject
   Logger log;

   @Test
   public void testRegister() throws Exception {
      Member newMember = memberRegistration.getNewMember();
      newMember.setName("Jane Doe");
      newMember.setEmail("jane@mailinator.com");
      newMember.setPhoneNumber("2125551234");
      memberRegistration.register();
      assertNotNull(newMember.getId());
      log.info(newMember.getName() + " was persisted with id " + newMember.getId());
   }

   @Produces
   public Logger produceLog(InjectionPoint injectionPoint) {
      return Logger.getLogger(injectionPoint.getMember().getDeclaringClass());
   }
   
}

JBOSS_HOMEの設定やらMavenリポジトリの設定やらが適正であれば、以下のようにテストが成功する。
http://design.jboss.org/arquillian/logo/ui/images/success/arquillian_ui_success_64px.png*4

jboss-as-quickstarts-7.0.0.Final/kitchensink% mvn test -Parq-jbossas-managed
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building JBoss AS Quickstarts: Kitchensink 7.0.0.Final
[INFO] ------------------------------------------------------------------------
(略)
-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running org.jboss.as.quickstarts.kitchensink.test.MemberRegistrationTest
(略)
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.82 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 13.765s
[INFO] Finished at: Fri Aug 05 00:17:07 JST 2011
[INFO] Final Memory: 11M/298M
[INFO] ------------------------------------------------------------------------

ちなみに以下のアイコンもある。*5

Warning Failure Error
http://design.jboss.org/arquillian/logo/ui/images/warning/arquillian_ui_warning_64px.png http://design.jboss.org/arquillian/logo/ui/images/failure/arquillian_ui_failure_64px.png http://design.jboss.org/arquillian/logo/ui/images/error/arquillian_ui_error_64px.png


…明日は早起きしなくちゃいけないので今日はここまで。

*1:今のところ起動時間最速は私です

*2:AS7未対応

*3:このバージョンはプロジェクトのページからはまだ取得できない

*4:別にこのアイコンが画面上に出てくるわけじゃない

*5:これらも同じく画面上に出てくるわけじゃなくて、Artworkが提供されてるだけ