javaアプリケーション開発におけるユニットテストとtddの実践 java day tokyo...
DESCRIPTION
TRANSCRIPT
Javaアプリケーション 開発における
テストとTDDの実践
Shuji Watanabe (@shuji_w6e)
1
自己紹介
渡辺 修司 / @shuji_w6eJUnit実践入門(技術評論社)
クラスメソッド株式会社
札幌にて在宅勤務
AWS関連
ポータルサイト構築
Spring, Ember.js, d3-data
4刷!累計1万部
クラスメソッド札幌オフィス開設!AWSエンジニア / iOSエンジニア
U/Iターン歓迎!
7月初旬 開設予定!
アプリ屋から 移籍可能
Javaアプリケーション 開発における
テストとTDDの実践
Shuji Watanabe (@shuji_w6e)
5
Javaアプリケーション 開発における
テストとTDDの実践
Shuji Watanabe (@shuji_w6e)
6
Long live testing ?
http://www.flickr.com/photos/peakman2/1017866785/
_人人人人人人人人人_ > レガシーコード <  ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
http://www.flickr.com/photos/bsom/4625185702/
貴様のプロジェクトでは、効果的なテストをしてるか?
自動化テストの成熟度0 自動化されたテストを行っていない、標準出力
1 効果的とは言えないが、一部のテストを自動化している
2主要な部分のテストは自動化され、継続的インテグレーションなどの「自動化」をはじめている
3プロジェクト計画やアーキテクチャが自動化されたテス トを前提としている
4テストをはじめとした「自動化」が開発プロセスに組み込まれている
5自動化が開発プロセスに組み込まれ、プロジェクトやチームに合わせて改善を続けている
ユニットテストは基本スキル最初から出来る人はいません
たくさん書けばそれだけ覚えます
TDDBC, JJUG CCCなど勉強会にでましょう
社内でテスト勉強会をやりましょう
JUnit実践入門がオススメです!
http://www.flickr.com/photos/palermobootcamp/5464512672/
TDD!TDD!
テスト!テスト!
継続的インテグレーションと
ユニットテスト
手作業したら負け
継続的インテグレーションバージョン管理システムと連動
コミット毎にテストなどを自動実行
テスト失敗時に通知(メールなど)
簡単に導入可能
Jenkinsがスタンダード
自動化された開発環境の例
自動化のメリット手作業によるコストの削減
手作業によるミスの削減
コンピューティングリソースを有効活用
文句を言わずに繰り返し何度でも実行
楽しいw
http://www.flickr.com/photos/jas_132/5403388208
ユニットテストは 最高のパートナー
ユニットテストの特徴自動的に実行可能なプログラム
実行コスト < 実装コスト / 手動テスト
変更の影響がなければ常に成功を維持
早い段階から繰り返し実行することで 効果が最大となる
テストの実装時期とテスト回数
コード量/開発の進捗
テスト数
テスト 回数
A
B
C
テスト 回数
テスト 回数
変更毎にテストを実行ソースコードの修正の影響
可能な限り早く影響を検知
リグレッション(デグレーション)対策
× 防止する ○ 即座に修正できるようにする
Amazon EC2の活用Elasticなコンピューティングリソース
調達が容易
必要に応じて起動すればコストも削減
VPN接続も可能
簡単構築、簡単インストール
データベースを操作するメソッドのテスト
DAO, Repository, EntityManagerモデルの永続化を行うレイヤー
RDBとの通信部分を分離する
Hibernate, S2Dao などのフレームワーク
永続化層のユニットテスト戦略外部システムに依存する部分はモック派
外部システムに依存すべきでない
実行に時間がかかるのはよくない
RDBは実質的にシステム内部とみなす派
SQLやクエリ実行まで含めて実装
時間がかかってもテストしたい
4 Phase Test初期化 ー Setup テスト実行時の状態を一定にする 実行 ー Exercise テスト実行後の影響を観測する 検証 ー Verify 期待する結果となるかを検証する 後処理 ー Teardown 次のテストへの影響させない
初期化 ー SetupDBデータの初期化
関連テーブルの削除
シーケンス
システム時間
初期化にかかる処理時間
テスト用データの準備
すべて自前で行うのは かなり大変....
実行 ー Exerciseテスト対象オブジェクト(Daoなど)の準備
フレームワークのは単体で実行できるか?
コネクションプールやデータソース
トランザクション境界
1つのメソッド(SQL)毎にテストを実行
DBの状態によって結果も変わる
検証 ー Verifyモデルの検証
Assertion / Hamcrest Matcher API
シーケンス番号、システム時間などの除外
順番に注意(order by)
DBデータへの反映の検証
Create, Update, Deleteでは必須
後処理 ー Teardown1つのテストで複数のことを検証しない
次のテストの初期化に任せて何もしない
テスト失敗時、DBの状態が残る
テスト方針リアルDBを利用
フィクスチャはYAMLフォーマットで定義
初期化処理でDBをセットアップ
後処理ではDBを操作しない
JUnit, DbUnit, cmtest-db を利用
DbUnit JUnitの拡張フレームワーク
JUnit 3系
データベースの初期化と後処理
フィクスチャ(データ)
検証
http://dbunit.sourceforge.net/
public class SampleTest extends DBTestCase { protected void setUp() throws Exception { super.setUp(); DatabaseOperation.CLEAN_INSERT .execute(connection, dataSet); } public void testMe() throws Exception { IDataSet databaseDataSet = getConnection().createDataSet(); ITable actualTable = databaseDataSet.getTable("TABLE_NAME"); IDataSet expectedDataSet = new FlatXmlDataSetBuilder() .build(new File("expectedDataSet.xml")); ITable expectedTable = expectedDataSet.getTable("TABLE_NAME"); Assertion.assertEquals(expectedTable, actualTable); } }
cmtest-dbDbUnitのラッパーライブラリ
JUnit4対応
YAMLによるフィクスチャ
アノテーションによるテストの定義
JUnit4系のモダンなテストコードを実現
https://github.com/classmethod/cmtest/tree/master/cmtest-db
public class UserRepositoryTest { @Rule public DbUnitTester tester = DbUnitTester .forJdbc("com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/cmtest") .username("root").password("").create(); @Fixture(resources = "2-users.yaml") @Test public void updateによる更新() throws Exception { IDataSet expected = YamlDataSet .load(getClass().getResourceAsStream("yaml")); sut.update(user); tester.verifyTable("users", expected); } }
その他のポイントフィクスチャ重要
0件の場合、1件の場合、2件の場合
Enclosedテストランナーを活用
ローカル実行
スローテスト
システム時間など難しい部分は無視も一手