Java開発環境(ユニットテスト編)
ソフトウェアの品質を確保するということは、地道にひとつひとつ積み重ねていくことしかありません。品質の積み重ねなくして作り上げられたソフトウェアは砂上の楼閣でしかありません。しかしながら、往々にして地道な作業はスキップされ、砂上の楼閣を作ってしまってから、崩れるのを押し留めようという果てしない作業をしていることがあります。得てして、開発に携わる人数が多いほど、ステークホルダーが多いほどその傾向があるように思います。
ここでは、品質を確保する地道な作業のひとつであるユニットテストを容易にするための開発環境を構築することを検討します。
ユニットテストは、エクストリームプログラミングやテスト駆動開発などによって復権をはたしてきましたが、品質を確保する観点ではまだ十分とはいえません。一つは、まじめにユニットテストをしようとすると、スタブを作成する労力が膨大となってしまいます。
労力をはしょるために、スタブを作らず、いきなりクラスを結合した状態を作ってユニットテストを実行する、あるいは、低レイヤーのクラスから順次ボトムアップに作ってユニットテストを実行する、という一見効率を改善したかのような作業をしてしまう場合もあります。この両者は実はユニットテストではなく結合テストをしている、つまりユニットテストをやっていたつもりが省略してしまっていた、という状況です。
ユニットテストをするならば、やはりカバレッジは外せませんが、結合した状態ではなかなかカバレッジを確保することが困難です。カバレッジ確保には、ユニットテストのドライバ側での制御だけでは不十分で、スタブ側でいろいろな想定ケースに対応する処理を書く必要があります。特に、エラー処理コードをカバレッジするにはスタブ側で擬似的にエラーを生じる仕掛けなしには困難です。
以前経験したプロジェクトでは、完全なユニットテストを実施せず、スタブを作成する手間を省くため、ボトムアップ結合での半ユニット半結合テストを行ったので、どうしてもカバレッジを100%にできず、困ったことがあります。
そこで、ユニットテストにおける作業効率を上げるには、スタブをいかに簡単に作成するかがポイントの一つとなります。Javaでは、ユニットテストにおいてスタブとして機能するオブジェクトを簡単に生成するためのツール(Mockツール)がいくつか存在しています。
スタブ生成(Mock)ツールのリストアップ
ツール名 | バージョン | リリース日 | 備考 |
---|---|---|---|
EasyMock | 3.0 | 2010-05-08 | |
jMock | 2.5.1 | 2008-08-24 | |
Mockito | 1.8.5 | 2010-05-26 |
EasyMock
使い方は、以下記事で把握しました。
現時点では、インタフェースでないクラスのモックを生成することができるようになっています。なお、EasyMockだけでは、finalクラスのモックは生成できません。また、finalメソッドをモック対象にすることもできません。後述のJDave unfinalizerを使用すると可能となります。
使用メモ
EasyMockは、cglibとObjenesisの2つの外部ライブラリに依存しているとあるので、両者をダウンロードして合わせてクラスパスに入れています。なお、cglibは、ASMを含んだcglib-nodep-2.2.jarをダウンロードし使用します。
jMock
インタフェースでないクラスのモックを生成することができますが、その場合、追加でいくつかのライブラリが必要になります。
cglib, objenesis, jmock-legacy
finalクラスやfinalメソッドのモックを作成する場合は、JDaveライブラリを使えとあります。これを使うなら、EasyMockでもfinalクラス・finalメソッドのモックは可能かもしれません。
Mockito
概要を以下の記事で把握しました。
同記事によれば、使い勝手は一番よいらしいです。
finalクラス、匿名クラスのモックは作成できません。また、staticメソッドもモック対象とできません。
JDaveのunfinalizer
JavaVMに-javaagentオプションで指定し、以降ロードするクラス・メソッドのfinal指定を解除するものです。通常Mockライブラリは、モック対象クラスのサブクラスを生成するので、モック対象クラス(メソッド)がfinalアクセス修飾子指定されていると、実行できません。そこで、Javaバイトコード・インストゥルメンテーションでこのfinalアクセス修飾子を解除します。
使用法
JDaveホームページより、JDaveをダウンロードします。ホームページから、[Resources]リンクをたどって、[Download]リンクをたどってダウンロードしたファイル(jdave-parent-1.1.zip)を展開します。展開した中にlib/jdave-unfinalizer-1.1.jarがあるので、これをJavaVM起動時に-javaagentオプションで指定します。
また、このjdave-unfinalizerは、ASMを使用しているので、ASMも合わせてダウンロードし、クラスパスに追加します。
$ java -javaagent:/java/jdave-parent-1.1/lib/jdave-unfinalizer-1.1.jar -cp /java/asm-3.3/lib/asm-3.3.jar:. MyClass
モックとコーディング規約
モック作成にあたっては、finalなクラスはだめなので、本来はfinal指定が望ましいクラスも、ユニットテスト上はfinal指定しないというのが現実的です。ということで、極力finalをつけるというルールを降ろさなくてはならないようです。