コンテナでテストをまわせ!
Java EEへの自動テストの導入
小西 高之
2
コンテナでテストをまわせ!
Twitterハッシュタグ: #jt12_b202
小西 高之
とあるプロジェクトで...
『これからアプリケーションのテストを始める』
『はい!』
6
8
10
今日話すこと
自動テストの考え方
テストフレームワークのご紹介
デモ
実際のプロジェクトへの適用
まとめ
12
Java EE 6 Architecture
Web Container
JSP
Servlet
JSF, CDI, JPA,
JMS, JAX-RS,
JACC, JTA, ...
EJB Container
EJB
CDI, JPA, JMS,
JAX-RS, JACC,
JTA, ...
Application
Client Container
Client
CDI, JPA, JMS,
...
Applet Container
Client
Database
自動テスト
メリット
リグレッションテスト
再現可能
実行時に人手が不要
デメリット
テスト作成
メンテナンス
14
容易/簡単
困難/複雑
大
小
効果
各テスト自動化の
難易度と効果
テストの作成・メンテナンス・
実行前処理・実行・結果確認・
事後処理の難易度
テストの明確さ、テスト対象の
変更可能性などによる自動化の
効果
容易/簡単
困難/複雑
大
小
効果
優先的に
テストを作成
自動化以外の
方法を考える
16
テストの分類
Unit Test
Integration Test
Unit Test
個々のクラスのテスト
JVM内で閉じている
実行速度が速い
Java EE 5以降、容易にテストできるようになった
コンテナの機能を補うためのオブジェクトが必要
18
Integration Test
コンポーネントのテスト
例)秘密鍵ファイルを使ってXMLに署名する
System Test
フィーチャーのテスト
例)ユーザーとしてシステムにユーザー情報を登録する
20
容易/簡単
困難/複雑
大
小
効果
Unit Test
容易/簡単
困難/複雑
大
小
効果
22
容易/簡単
困難/複雑
大
小
効果
System Test
Integration Testの問題点
テスト作成が大変
実行に時間がかかる
テストコードが脆い
効果は期待できるが、テスト作成、維持にコストが
かかる
24
容易/簡単
困難/複雑
大
小
効果
Integration Test
容易/簡単
困難/複雑
大
小
効果
28
30
Integration Test
Framework のご紹介
32
Web Container
JSP
Servlet
JSF, CDI, JPA,
JMS, JAX-RS,
JACC, JTA, ...
EJB Container
EJB
CDI, JPA, JMS,
JAX-RS, JACC,
JTA, ...
複数のコンテナに対応
Java EE Containers
Web Containers
EJB Containers
CDI Containers
https://docs.jboss.org/author/display/ARQ/Supported+containers
Arquillianの特徴
Arquillianの特徴
JUnit/TestNGのテストケースとしてテストを作成
ビルドツール非依存
IDEの自動ビルド機能と連携
拡張可能
34
Arquillian利用プロジェクトの例
Seam 3
http://seamframework.org/Seam3
Apache DeltaSpike
https://cwiki.apache.org/DeltaSpike/
JBoss AS 7
http://www.jboss.org/as7
JBoss RHQ
http://www.jboss.org/rhq
例
36
/**
* A component for creating personal greetings.
*/
public
class
Greeter {
public
void
greet(PrintStream to, String name) {
to.println(createGreeting(name));
}
public
String createGreeting(String name) {
return
"Hello, "
+ name +
"!"
;
}
}
@RunWith(Arquillian.class)
public class GreeterTest { @Deployment
public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }
@Inject
Greeter greeter; @Test
public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); }
}
38
@RunWith(Arquillian.class)
public class GreeterTest { @Deployment
public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }
@Inject
Greeter greeter; @Test
public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); }
}
GreeterTest.java
@RunWith(Arquillian.class)
public class GreeterTest { @Deployment
public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }
@Inject
Greeter greeter; @Test
public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); }
}
greeterをインジェクト
40
@RunWith(Arquillian.class)
public class GreeterTest { @Deployment
public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }
@Inject
Greeter greeter; @Test
public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); }
}
テストアーカイブを指定
@RunWith(Arquillian.class)
public class GreeterTest { @Deployment
public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Greeter.class)
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }
@Inject
Greeter greeter; @Test
public void should_create_greeting() { Assert.assertEquals("Hello, Earthling!", greeter.createGreeting("Earthling")); greeter.greet(System.out, "Earthling"); }
}
42
デモの実行環境
Weld 1.1.1.Final
embedded
GlassFish 3.1
embedded
JBoss AS 7.1.0.Final
managed
44
Container management
Embedded
Remote
J
Unit
46
Arquillian class
(extends
BlockJUnit4ClassRunner)
J
U
Managed mode
JAR file
arquillian service
boot
48
run tests
shutdown
undeploy
correct result
50
result
J
U
52
ふりかえり
テスト実行速度について
IDEの自動ビルドを利用
実プロジェクトへの適用
既存のコードへの適用
DB、ネットワーク
54
実プロジェクトへの適用
既存のコードへの適用
DB、ネットワーク
画面遷移
arquillian-showcaseを参照してください
CDI, EJB, EJB(TestNG), JAX-RS, JAX-WS, JMS, JPA, JPA-Lite, JSF, OSGi,
Servlet, UI(Selenium)
実プロジェクトへの適用
既存のコードへの適用
DB、ネットワーク
56
58
60
容易/簡単
困難/複雑
大
小
効果
徐々に
テストを追加
優先的に
テストを作成
既存コードへの
自動テストの適用
DEMO
既存コードの例:OpenAM
WARファイルを読み込んで、テストアーカイブを作成
テストを実行
コンテナ:JBoss Enterprise Application Platform 5.1.2
OpenAM
62
DEMO
64
これまでの
Integration Test
テスト作成が大変
実行に時間がかかる
テストコードが脆い
効果は期待できるが、テスト作成、維持にコストが
かかる
作成、管理、実行が容易
実行が高速
テストコードが脆くない
66
容易/簡単
困難/複雑
大
小
効果
Integration Test
コンテナでテストをまわせ!
Java EEへの自動テストの導入
68
References
Arquillian - JBoss Community
http://www.jboss.org/arquillian
Shrinkwrap - JBoss Community
http://www.jboss.org/shrinkwrap/
Real Java Enterprise Testing
http://slidesha.re/q06oXs
Throwing complexity over the wall: Rapid development for enterprise
Java http://slidesha.re/vl8Hkw JUnit http://junit.org/ Git http://git-scm.com/ Jenkins CI http://jenkins-ci.org/http://slidesha.re/vl8Hkw CloudBees http://www.cloudbees.com/ JBoss Tools http://www.jboss.org/tools レガシーコード改善ガイド (Michael C. Feathers 著/ウルシステムズ株式会社 監訳 / 平澤章、越智 典子、稲葉信之、田村友彦、小堀真義 訳 / 翔泳社 刊)
Growing Object-Oriented Software Guided by Tests (Steve Freeman、Nat Pryce 著 / Addison-Wesley 刊) Jenkins
(John Ferguson Smart 著 / Sky株式会社 玉川 竜司 訳 / オライリージャ パン 刊)
Jenkins実践入門
(佐藤聖規(監修)、和田貴久、河村 雅人、米沢 弘樹、山岸 啓 著 / 川口 耕介 監修 / 技術評論社 刊)
xUnit Test Patterns