タイトル
 メニューにないコーナーはTopからいけます
TOPJavaテスト → This Page

JUnit(JUnit4)の概要〜利用方法【ユニットテスト - テスト】

前提

このページに記載している内容は2011/01/23に書かれたものです。
掲載している画面や方法が将来的に変更されている場合があります。
また、解説に使っている eclipse のバージョンは 3.6.1 です。
eclipseのバージョンによって若干異なる部分があるかもしれません。
「初心者にも分かる JUnit(JUnit4)」を目指して頑張って解説します。

特徴

・JUnit3の改良版
・eclipseと連携していて簡単にテスト実行&失敗したテストの理由を表示
・JUnit3の以下の問題点を改良
 ・テストメソッドの名称が固定
  →メソッドにアノテーションを付加することで対応
 ・例外が発生するテストが複雑
  →アノテーションで期待する例外を記述することで対応
 ・テスト前後処理のバリエーションが少ない
  →テストクラス前後処理など、いくつかのバリエーションが追加された
・JUnit3と同じ問題点
 ・テストメソッドに引数を渡せない
 ・テストメソッドの数だけインスタンスが生成される
 (→これは分離の思想でわざとこう設計されているのでメリットもある)

導入方法

eclipse3.2から標準で用意されています。

利用方法

テスト対象クラスの作成

まずはテスト対象となるクラスを作成します。
今回は以下のような検証用クラスを作ってみました。

ValidatorUtility.java
package jp.co.junit4.sample;

/**
 * 検証ユーティリティクラス
 */
public class ValidatorUtility {

	/**
	 * ブランクチェック
	 * 
	 * @param value
	 *            値
	 * @return ブランク有無
	 */
	static public boolean isBlank(String value) {
		if (value == null || value.length() == 0) {
			return true;
		}
		return false;
	}

	/**
	 * int値チェック
	 * 
	 * @param value
	 *            文字列
	 * @return int値判定有無
	 */
	static public boolean isInt(String value) {
		if (isBlank(value)) {
			return false;
		}
		try {
			Integer.parseInt(value);
		} catch (NumberFormatException e) {
			return false;
		}
		return true;
	}

}

テストソース用フォルダの作成

とっととテストクラスを作りたいところですが、ここはぐっと我慢してまずはテストソース用フォルダを作成しましょう。
実ソースとテストソースが同じフォルダにあった場合、ある程度の規模のプロジェクトになるとかなり鬱陶しいことになるので。

画面左側の「プロジェクト・エクスプローラー」でプロジェクトを右クリックしてしてメニューから「新規」>「ソース・フォルダ」を選択します。
図:メニュー「新規」「ソース・フォルダ」

「新規ソース・フォルダ」画面が表示されたら「フォルダー名」に test と入力して「完了」ボタンを押します。
図:「新規ソース・フォルダ」画面

するとプロジェクトの src フォルダと同列の場所に test フォルダが作成されたと思います。
図:作成後

テストクラスの作成

ではテストクラスを作ってみましょう。

画面左側の「プロジェクト・エクスプローラー」でテスト対象となるクラスを右クリックしてメニューから「新規」>「その他」を選択します。
図:メニュー「新規」「その他」

「新規」画面が表示されたらツリーから「Java」>「JUnit」>「JUnitテスト・ケース」を選択して
「次へ」ボタンを押します。
図:「新規」画面

「新規JUnitテスト・ケース」画面が表示されたらまずは「ソース・フォルダー」右側の「参照」ボタンを押します。
図:「新規JUnitテスト・ケース」画面

「ソース・フォルダーの選択」画面が表示されたら先ほど作成した test フォルダーを選択して「OK」ボタンを押します。
図:「ソース・フォルダーの選択」画面

「新規JUnitテスト・ケース」画面に戻ったら「ソース・フォルダー」欄の内容が変わっていると思います。
画面の各種項目は以下のようになっています。
項目概要
新規JUnit3テスト/新規JUnit4テスト 本ページはJUnit4の解説なので「新規JUnit4テスト」を選択しましょう。
パッケージ テストクラスを作成する先のパッケージです。基本的にはそのままでいいでしょう。
名前 テストクラス名です。基本的にはそのままでいいでしょう。
スーパークラス テストクラスの継承元となるクラスです。基本的にはそのままでいいでしょう。
setUpBeforeClass テストクラスにsetUpBeforeClassメソッドを自動生成してくれます。今回はチェックをつけましょう。
tearDownAfterClass テストクラスにtearDownAfterClassメソッドを自動生成してくれます。今回はチェックをつけましょう。
setUp テストクラスにsetUpメソッドを自動生成してくれます。今回はチェックをつけましょう。
tearDown テストクラスにtearDownメソッドを自動生成してくれます。今回はチェックをつけましょう。
コンストラクター JUnit4では使用できません。
コメントの生成 コメントを自動生成してくれます。今回はチェックをつけましょう。
テスト元クラス テスト元のクラスです。基本的にはそのままでいいでしょう。
上記項目を正しく設定したら「次へ」ボタンを押します。
図:「新規JUnitテスト・ケース」画面

「JUnit 4 がビルド・パスにありません。追加しますか?」
と表示されたら「JUnit 4 ライブラリーをビルド・パスに追加」を選択して「OK」ボタンを押しましょう。

次の画面は自動生成させたいテストメソッドを選択する画面です。
ツリーにはテスト対象のクラスが持つメソッド、そしてテスト対象クラスの親クラスが持つメソッドを選べます。
今回は親クラス(Objectクラス)のテストは不要なので、ValidatorUtility クラスだけチェックを入れます。
チェックが終わったら「完了」ボタンを押します。
図:「新規JUnitテスト・ケース」2画面

すると test フォルダにテストクラスが作成されています。
コメントやメソッドも自動生成されていますね。
プロジェクトの下に JUnit4 ライブラリも追加されています。
図:基本画面

テストクラスの実装

では作成したテストクラスの中身を実装していきましょう。

自動生成されたメソッドはそれぞれ以下のような役割を持っています。
・setUpBeforeClassメソッド
  このテストクラスの最初のテストメソッドが呼び出される前に実行されるメソッドです。
・tearDownAfterClassメソッド
  このテストクラスの最後のテストメソッドが呼び出された後に実行されるメソッドです。
・setUpメソッド
  各テストメソッドが呼び出される前に実行されるメソッドです。
・tearDownメソッド
  各テストメソッドが呼び出さた後に実行されるメソッドです。
・testIsBlankメソッド
  テスト対象クラスの isBlank メソッドに対するテストメソッドです。
・testIsIntメソッド
  テスト対象クラスの isInt メソッドに対するテストメソッドです。

メソッド名の上に @xxxxx とあるのは Java5 から導入されたアノテーションと呼ばれるものです。
アノテーションについてはここでは解説対象外とさせて下さいm(_ _)m
(そもそもアノテーションはJUnitの機能というわけではないので)

まずはそれぞれのメソッドがどのような順番で呼び出されるかを確認するために
以下のようなソースにしてみます。

ValidatorUtilityTest.java
package jp.co.junit4.sample;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * @author みっちー
 * 
 */
public class ValidatorUtilityTest {

	/**
	 * @throws java.lang.Exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		System.out.println("setUpBeforeClass");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		System.out.println("tearDownAfterClass");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		System.out.println("setUp");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		System.out.println("tearDown");
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isBlank(java.lang.String)}
	 * のためのテスト・メソッド。
	 */
	@Test
	public void testIsBlank() {
		System.out.println("testIsBlank");
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。
	 */
	@Test
	public void testIsInt() {
		System.out.println("testIsInt");
	}
}

では早速実行してみましょう。
画面左側の「プロジェクト・エクスプローラー」で ValidatorUtilityTest を右クリックしてメニューから「実行」>「JUnitテスト」を選択します。
図:メニュー「実行」「JUnitテスト」

「JUnit」ビュー、「コンソール」ビューが追加されて実行結果が表示されると思います。
図:「コンソール」ビュー

「コンソール」ビューの実行結果を見ると以下のような順番でメッセージが表示されていると思います。

1.setUpBeforeClass
2.setUp
3.testIsBlank
4.tearDown
5.setUp
6.testIsInt
7.tearDown
8.tearDownAfterClass

以下、解説です。
最初にテストクラスの最初のテストメソッドが呼び出される前に実行される setUpBeforeClass メソッドが実行されます。
次にテストメソッドの前後で setUp、tearDown メソッドが実行されるので
testIsBlank メソッドのセットとして setUp→testIsBlank→tearDown メソッド、
testIsInt メソッドのセットとして setUp→testIsInt→tearDown メソッドと実行されます。
最後にテストクラスの最後のテストメソッドが呼び出された後に実行される tearDownAfterClass メソッドが実行されます。


次に「JUnit」ビューを確認してみましょう。
ツリーが緑色のチェックが付いていて、エラー0、失敗0となっていると思います。
テストメソッドにメッセージ表示のコードしか記述していないので成功したからです。

さらに testIsBlank、testIsInt メソッドを以下のように変更してみましょう。
import にも一行追加します。
ValidatorUtilityTest.java(一部抜粋)
import static org.junit.Assert.assertTrue;

・・・略・・・

	@Test
	public void testIsBlank() {
		assertTrue(ValidatorUtility.isBlank(null));
	}

	@Test
	public void testIsInt() {
		assertTrue(ValidatorUtility.isInt(null));
	}

急に assertTrue というメソッドが出てきたと思います。
このメソッドは org.junit.Assert クラスが持つ検証メソッドです。
Assert クラスが持つ検証メソッドは以下の通りです。
検証メソッド概要
assertArrayEquals 期待値と実績値が等しい場合は正常終了。等しくない場合は失敗終了する。
assertEquals 期待値と実績値が等しい場合は正常終了。等しくない場合は失敗終了する。
assertFalse 実績値が false の場合は正常終了。true の場合は失敗終了する。
assertNotNull 実績値が null でない場合は正常終了。null の場合は失敗終了する。
assertNotSame 期待値と実績値が同じ参照をしていない場合は正常終了。同じ参照をしている場合は失敗終了する。
assertNull 実績値が null の場合は正常終了。null でない場合は失敗終了する。
assertSame 期待値と実績値が同じ参照をしている場合は正常終了。同じ参照をしていない場合は失敗終了する。
assertTrue 実績値が true の場合は正常終了。false の場合は失敗終了する。
fail このメソッドが実行されると失敗終了する。

と、いうことで上記で修正したコードは
・testIsBlank では ValidatorUtility.isBlank メソッドに null を渡して実行したら true が返されて正常終了するはず。
・testIsInt では ValidatorUtility.isInt メソッドに null を渡して実行したら true が返されて正常終了するはず。
というコードになっています。
が、しかし実際には ValidatorUtility.isInt メソッドに null を渡したら false が返されるので失敗終了します。
では ValidatorUtilityTest クラスを実行してみましょう。

先ほどと同様の手順で実行してみて下さい。
実行完了後、「JUnit」ビューを確認すると失敗1になっていると思います。
「JUnit」ビューの左側のツリーで失敗となったメソッドは赤色のチェックが付いています。
失敗となった isInt メソッドを選択すると、「JUnit」ビューの右側に失敗となった原因の詳細が表示されます。
さらに、障害トレースの at jp.co.junit4.sample.ValidatorUtilityTest.isInt(ValidatorUtilityTest.java:64) をダブルクリックすると
Javaコード・エディターでテストクラスの該当箇所に遷移できます。
図:「JUnit」ビュー2

さて、おおよその使い方も分かったと思うのでテストクラスを完成させましょう。
今のままでは isBlank メソッドのテストも不十分、isInt メソッドはそもそも失敗ですからね。

以下、テストクラスの完成形サンプルです。
ValidatorUtilityTest.java
package jp.co.junit4.sample;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * @author みっちー
 * 
 */
public class ValidatorUtilityTest {

	/**
	 * @throws java.lang.Exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		System.out.println("setUpBeforeClass");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		System.out.println("tearDownAfterClass");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		System.out.println("setUp");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		System.out.println("tearDown");
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isBlank(java.lang.String)}
	 * のためのテスト・メソッド。(null)
	 */
	@Test
	public void isBlank_01() {
		System.out.println("isBlank_01");
		assertTrue(ValidatorUtility.isBlank(null));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isBlank(java.lang.String)}
	 * のためのテスト・メソッド。(空白)
	 */
	@Test
	public void isBlank_02() {
		System.out.println("isBlank_02");
		assertTrue(ValidatorUtility.isBlank(""));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isBlank(java.lang.String)}
	 * のためのテスト・メソッド。(正常)
	 */
	@Test
	public void isBlank_03() {
		System.out.println("isBlank_03");
		assertFalse(ValidatorUtility.isBlank("xxxxx"));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。(null)
	 */
	@Test
	public void isInt_01() {
		System.out.println("isInt_01");
		assertFalse(ValidatorUtility.isInt(null));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。(空白)
	 */
	@Test
	public void isInt_02() {
		System.out.println("isInt_02");
		assertFalse(ValidatorUtility.isInt(""));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。(数値以外)
	 */
	@Test
	public void isInt_03() {
		System.out.println("isInt_03");
		assertFalse(ValidatorUtility.isInt("x"));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。(正常)
	 */
	@Test
	public void isInt_04() {
		System.out.println("isInt_04");
		assertTrue(ValidatorUtility.isInt("123456"));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。(正常マイナス値)
	 */
	@Test
	public void isInt_05() {
		System.out.println("isInt_05");
		assertTrue(ValidatorUtility.isInt("-123456"));
	}

	/**
	 * {@link jp.co.junit4.sample.ValidatorUtility#isInt(java.lang.String)}
	 * のためのテスト・メソッド。(int桁あふれ)
	 */
	@Test
	public void isInt_06() {
		System.out.println("isInt_06");
		assertFalse(ValidatorUtility.isInt("12345678901234567890"));
	}
}


isBlank メソッドに対するテストメソッドを3つ、isInt メソッドに対するテストメソッドを6つ作成しました。
JUnit3 と違って JUnit4 ではテストメソッドの名前の先頭を test にする必要はありません。
本当にそれでも動作するのかを確認するため、テストメソッドの名前の先頭はわざと変えています。

実行してみると全て成功し、「JUnit」ビューは以下の図のようになると思います。
図:「JUnit」ビュー3

テスト・スイートの作成

さて、ここまでくれば「あなたも立派なJUnit使い」と言いたいところですが、
まだ完璧ではありません。

たくさんのクラスを作り、それに対するたくさんのテストクラスを作った場合、
いちいち1つ1つ「右クリック」>「実行」>「JUnitテスト」なんて操作はやってられません。
まだ自分が作成したものだけならいいですが、開発リーダが各メンバーのテスト状況を見たくて
全部実行しなきゃいけないなんてなったら大変です。

そこで、テスト・スイートというものを作成します。
テスト・スイートとは簡単に言うと複数のテストを一括で実行できるものです。

クラスが1つだと寂しいし作る意味がないので、サンプルとしてもう1クラス追加しましょう。

テスト対象クラス
ConvertorUtility.java
package jp.co.junit4.sample;

/**
 * 変換ユーティリティクラス
 */
public class ConvertorUtility {

	/**
	 * nullをブランク文字列に変換する
	 * 
	 * @param value
	 *            文字列
	 * @return nullをブランク文字列に変換した結果文字列
	 */
	static public String nullToBlank(String value) {
		if (value == null) {
			return "";
		}

		return value;
	}

	/**
	 * 2つの文字列をハイフン区切りで結合
	 * 
	 * @param value1
	 *            文字列1
	 * @param value2
	 *            文字列2
	 * @return ハイフン区切りで結合した文字列
	 */
	static public String concatHyphen(String value1, String value2) {
		if (value1 == null) {
			value1 = "";
		}
		if (value2 == null) {
			value2 = "";
		}

		return value1 + "-" + value2;
	}
}

テストクラス
ConvertorUtilityTest.java
package jp.co.junit4.sample;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * @author みっちー
 * 
 */
public class ConvertorUtilityTest {

	/**
	 * @throws java.lang.Exception
	 */
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		System.out.println("setUpBeforeClass");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@AfterClass
	public static void tearDownAfterClass() throws Exception {
		System.out.println("tearDownAfterClass");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		System.out.println("setUp");
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		System.out.println("tearDown");
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#nullToBlank(java.lang.String)}
	 * のためのテスト・メソッド。(nullをブランクに)
	 */
	@Test
	public void nullToBlank_01() {
		System.out.println("nullToBlank_01");
		assertEquals("", ConvertorUtility.nullToBlank(null));
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#nullToBlank(java.lang.String)}
	 * のためのテスト・メソッド。(ブランクをブランクに)
	 */
	@Test
	public void nullToBlank_02() {
		System.out.println("nullToBlank_02");
		assertEquals("", ConvertorUtility.nullToBlank(""));
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#nullToBlank(java.lang.String)}
	 * のためのテスト・メソッド。(文字列はそのまま)
	 */
	@Test
	public void nullToBlank_03() {
		System.out.println("nullToBlank_03");
		assertEquals("xyz", ConvertorUtility.nullToBlank("xyz"));
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#concatHyphen(java.lang.String, java.lang.String)}
	 * のためのテスト・メソッド。(null+null)
	 */
	@Test
	public void concatHyphen_01() {
		System.out.println("concatHyphen_01");
		assertEquals("-", ConvertorUtility.concatHyphen(null, null));
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#concatHyphen(java.lang.String, java.lang.String)}
	 * のためのテスト・メソッド。(null+文字列)
	 */
	@Test
	public void concatHyphen_02() {
		System.out.println("concatHyphen_02");
		assertEquals("-xyz", ConvertorUtility.concatHyphen(null, "xyz"));
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#concatHyphen(java.lang.String, java.lang.String)}
	 * のためのテスト・メソッド。(文字列+null)
	 */
	@Test
	public void concatHyphen_03() {
		System.out.println("concatHyphen_03");
		assertEquals("abc-", ConvertorUtility.concatHyphen("abc", null));
	}

	/**
	 * {@link jp.co.junit4.sample.ConvertorUtility#concatHyphen(java.lang.String, java.lang.String)}
	 * のためのテスト・メソッド。(文字列+文字列)
	 */
	@Test
	public void concatHyphen_04() {
		System.out.println("concatHyphen_04");
		assertEquals("abc-xyz", ConvertorUtility.concatHyphen("abc", "xyz"));
	}
}

上記2つのクラスが完成したら「パッケージ・エクスプローラー」は以下の図のようになっていると思います。
図:パッケージ・エクスプローラー


次にいよいよテスト・スイート・クラスの作成ですが、JUnit3 までは eclipse でウィザード形式で作成できたのに、
なぜか JUnit4 はウィザード形式で作成できません。
(正確には JUnit3 形式で作成されてしまうので使い物にならない)

そこで直接 test フォルダの jp.co.junit4.sample パッケージに以下のようなクラスを作りましょう。

テストクラス
AllTests.java
package jp.co.junit4.sample;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ ConvertorUtilityTest.class, ValidatorUtilityTest.class})
public class AllTests {
}

RunWithアノテーションはおまじないのようなものです。
あまり深く考えずに毎回これを記述すればいいやと思って下さい。
SuiteClassesアノテーションに一括実行したいテスト・クラスを記述します。

では AllTests を実行してみましょう。
実行方法は通常のテスト・クラスと同様です。

実行が終了して「JUnit」ビューを開くと全てのテスト・クラスが実行されて全て成功となっているはずです。
以下の図は「JUnit」ビューのツリーを展開した状態です。
図:「JUnit」ビュー4

以上、ここまでできればあなたも「立派なJUnit使い」です。


と、テスト・スイートについて説明しましたが、実は eclipse からの実行だと
「プロジェクト・エクスプローラー」で test フォルダを右クリックして「実行」>「JUnit」だけでも
パッケージ以下のテストを一括実行できたりします。
ただし、この方法だとパッケージ以下の全てのテストを実行してしまうので、
まだ実行させたくないテスト・クラスがあったりする場合はテスト・スイートを作成して明示的に実行対象のテスト・クラスを記述したほうがいいです。

ダウンロード

解説で使ったクラスなどを含んだ eclipse 用プロジェクト一式

更新履歴

2011/01/23 新規作成


TOPJavaテスト → This Page
Valid CSS!