JMockitとはなんぞや~?
お馴染みのパターンですが...パターン化が大事って先生も仰っていました!
いまのところ、JUnitには、モックを扱う仕組みが実装されていないため、別のライブラリを追加する必要があるようです。
など、Java用のモックフレームワークには様々なものがあるようです。
テストにおけるモックの役割
モックとは、テスト対象から呼び出されるクラスを代替するクラスのことのようです。テストクラスはできてるけど、テストしたいクラスがまだ完成してないときに差し替えて利用します。
モックを利用することで、
- モックが呼び出された回数
- 実行された順番
- 引数の値
など、クラスの内部の動作をより詳細に検証できるようです。
JMockitを利用するための環境を構築
「ファイル」>「新規」>「その他」 をクリック。
「Maven」>「Mavenプロジェクト」を選択し、「次へ(N)>」をクリック。
「シンプルなプロジェクトの作成(S)(アーキタイプ選択のスキップ)」にチェックを入れ、「次へ(N)>」をクリック。
「グループ id:」「アーティファクト id:」を入力し、「完了(F)」をクリック。
プロジェクトの中の「pom.xml」ファイルを編集していきます。が、その前に、『JUnit』のバージョンを確認しておきます。Eclipse NEONでは、デフォルトで『org.junit_4.12.0.v201504281640』となっているので、『JUnit 4.12』を利用しているということだと思われます。
そして、指定する『JMockit』のバージョンについて参考書籍には説明がなかったので、バージョンは書籍に合わせることにしました。
編集前
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>tutorial</groupId> <artifactId>jMockitTest</artifactId> <version>0.0.1-SNAPSHOT</version> </project>
編集後
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>tutorial</groupId> <artifactId>jMockitTest</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.jmockit</groupId> <artifactId>jmockit</artifactId> <version>1.19</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project>
編集後、pom.xmlを保存すると、自動的に、『JMockit』と『JUnit』がインストールされました。『Maven 依存関係』でインストールされたものが確認できます。
C:¥Users¥ユーザー名¥.m2¥repository フォルダに必要なライブラリがインストールされるみたいです。
Jmockitを利用してみる
まずは、プロジェクトの中の「src/main/java」 の上で右クリックし、「新規」>「パッケージ」を選択。
「名前(M):」を入力し「完了(F)」をクリック。
続いて、作成したパッケージ上で右クリックし、「新規」>「クラス」を選択。
「名前(M):」を入力し「完了(F)」をクリック。
同じ要領で、クラスをもう一つ作成しておきます。
package tutorial; public class RandomAdder { public int add() { RandomNumber rand = new RandomNumber(); // 乱数を生成 int a = rand.getRandomNumber(); int b = rand.getRandomNumber(); return a + b; } }
package tutorial; import java.util.Random; public class RandomNumber { public int getRandomNumber() { Random rand = new Random(); return rand.nextInt(10); } }
テストクラスを作成します。
「名前(M):」を入力し「完了(F)」をクリック。
ファイルを編集します。
package tutorial; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; public class RandomAdderTest { @Test public void testCase() { RandomAdder rand = new RandomAdder(); // 結果が乱数なので予想値が一定にならない assertThat(rand.add(), is(4)); } }
JUnitテスト実行してみます。プロジェクトを選択した状態で、 の▼をクリックし、「実行」>「JUnit テスト」を選択。
エラーが起きます。
実行するたびに結果が変化するテストのことを不安定なテストと呼び、単体テストとしては適さないようです。そこでモックの出番です。RandomNumberクラスをモック化し、毎回同じ戻り値を返すようにします。
package tutorial; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; import mockit.Mocked; import mockit.NonStrictExpectations; public class RandomAdderTest {
// モックオブジェクトの生成 @Mocked private RandomNumber mockRandNumber; @Test public void testCase() { RandomAdder rand = new RandomAdder(); // getRandomNumber() メソッドの戻り値を2と定義 new NonStrictExpectations() {{ mockRandNumber.getRandomNumber(); result = 2; }}; assertThat(rand.add(), is(4)); } }
JUnitテスト実行。
@Mocked アノテーションをクラスに付与すると、そのクラスをモックとして扱えます。戻り値を定義するだけの場合は、NonStrictExceptionsクラスでモックの動作を定義できるようです。
モックの実行回数を検証するテスト
新しくテストメソッドを追加します。
package tutorial; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; import mockit.Mocked; import mockit.NonStrictExpectations; import mockit.Verifications; public class RandomAdderTest { @Mocked private RandomNumber mockRandNumber; @Test public void testCase() { RandomAdder rand = new RandomAdder(); // getRandomNumber() メソッドの戻り値を2と定義 new NonStrictExpectations() {{ mockRandNumber.getRandomNumber(); result = 2; }}; assertThat(rand.add(), is(4)); } @Test public void testCount() { RandomAdder rand = new RandomAdder(); rand.add(); new Verifications() {{ mockRandNumber.getRandomNumber(); times = 2; }}; } }
JUnitテスト実行。
RandomAdder.javaで、getRandomNumber() メソッドが 2回実行されているため、テストは成功します。
今回はこのへんで。