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

TestNGの利用方法(基本編)【ユニットテスト - テスト】

前提

本ページは2ページ目です。

ページ1TestNGの概要〜利用準備【ユニットテスト - テスト】
ページ2TestNGの利用方法(基本編)【ユニットテスト - テスト】
ページ3TestNGの利用方法(応用編)【ユニットテスト - テスト】

利用方法

テスト対象クラスの作成

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

ValidatorUtility.java
package com.mitchy_world.testng.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 フォルダが作成されたと思います。
図:作成後

テスト・クラスの作成

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

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

「新規」画面が表示されたらツリーから「TestNG」>「TestNG class」を選択して「次へ」ボタンを押します。
図:「新規」画面

「New TestNG class」画面が表示されたら自動生成させたいテスト・メソッドを選択します。
「すべて選択」ボタンを押してメソッドにチェックを入れ、「次へ」ボタンを押します。
図:「New TestNG class」画面

次の画面の各種項目は以下のようになっています。
項目概要
ソース・フォルダー テスト・対象クラスを作成する先のフォルダーです。
パッケージ名 テスト・クラスを作成する先のパッケージです。基本的にはそのままでいいでしょう。
クラス名 テスト・クラスのクラス名です。基本的にはそのままでいいでしょう。
@BeforeMethod テスト・クラスにbeforeMethodメソッドを自動生成してくれます。今回はチェックをつけましょう。
@AfterMethod テスト・クラスにafterMethodメソッドを自動生成してくれます。今回はチェックをつけましょう。
@DataProvider テスト・クラスにdpメソッドを自動生成してくれます。今回はチェックをつけましょう。
@BeforeClass テスト・クラスにbeforeClassメソッドを自動生成してくれます。今回はチェックをつけましょう。
@AfterClass テスト・クラスにafterClassメソッドを自動生成してくれます。今回はチェックをつけましょう。
@AfterTest テスト・クラスにafterTestメソッドを自動生成してくれます。今回はチェックをつけましょう。
@BeforeTest テスト・クラスにbeforeTestメソッドを自動生成してくれます。今回はチェックをつけましょう。
@AfterSuite テスト・クラスにafterSuiteメソッドを自動生成してくれます。今回はチェックをつけましょう。
@BeforeSuite テスト・クラスにbeforeSuiteメソッドを自動生成してくれます。今回はチェックをつけましょう。
XML suite file 作成するテスト・スイート・ファイルを指定します。今回は testngsample.xml と入力しましょう。

上記項目を正しく設定したら「完了」ボタンを押します。
図:「New TestNG class」画面2

すると test フォルダにテスト・クラスと xml ファイルが作成されています。
テスト・クラスにはメソッドも自動生成されていますね。
図:基本画面

テスト・クラスの実装

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

自動生成されたメソッドはそれぞれ以下のような役割を持っています。
・dpメソッド
  テストデータを取得するためのメソッドです。
・beforeSuiteメソッド
  各テスト・スイートが呼び出される前に実行されるメソッドです。
・afterSuiteメソッド
  各テスト・スイートが呼び出さた後に実行されるメソッドです。
・beforeTestメソッド
  各テストが呼び出される前に実行されるメソッドです。
・afterTestメソッド
  各テストが呼び出さた後に実行されるメソッドです。
・beforeClassメソッド
  各テスト・クラスが呼び出される前に実行されるメソッドです。
・afterClassメソッド
  各テスト・クラスが呼び出さた後に実行されるメソッドです。
・beforeMethodメソッド
  テスト・メソッドが呼び出される前に実行されるメソッドです。
・afterMethodメソッド
  テスト・メソッドが呼び出された後に実行されるメソッドです。
・isBlankメソッド
  テスト対象クラスの isBlank メソッドに対するテスト・メソッドです。
・isIntメソッド
  テスト対象クラスの isInt メソッドに対するテスト・メソッドです。

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

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

ValidatorUtilityTest.java
package com.mitchy_world.testng.sample;

import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class ValidatorUtilityTest {
	@BeforeMethod
	public void beforeMethod() {
		System.out.println("beforeMethod");
	}

	@AfterMethod
	public void afterMethod() {
		System.out.println("afterMethod");
	}

	@BeforeClass
	public void beforeClass() {
		System.out.println("beforeClass");
	}

	@AfterClass
	public void afterClass() {
		System.out.println("afterClass");
	}

	@BeforeTest
	public void beforeTest() {
		System.out.println("beforeTest");
	}

	@AfterTest
	public void afterTest() {
		System.out.println("afterTest");
	}

	@BeforeSuite
	public void beforeSuite() {
		System.out.println("beforeSuite");
	}

	@AfterSuite
	public void afterSuite() {
		System.out.println("afterSuite");
	}

	@Test
	public void isBlank() {
		System.out.println("isBlank");
	}

	@Test
	public void isInt() {
		System.out.println("isInt");
	}
}

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

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

ツリーに緑色のチェックが付いていて、右上に「パス済み:2 失敗:0」となっていると思います。
テスト・メソッドにメッセージ表示のコードしか記述していないので成功したからです。

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

beforeSuite
beforeTest
beforeClass
beforeMethod
isBlank
afterMethod
beforeMethod
isInt
afterMethod
afterClass
afterTest
afterSuite

以下、解説です。
最初にテスト・スイートの開始時に実行される beforeSuite メソッドが実行されます。
次にテストの開始時に実行される beforeTest メソッドが実行されます。
次にテスト・クラスの開始時に実行される beforeClass メソッドが実行されます。
次にテスト・メソッドの前後で beforeMethod、afterMethod メソッドが実行されるので
isBlank メソッドのセットとして beforeMethod→isBlank→afterMethod メソッド、
isInt メソッドのセットとして beforeMethod→isInt→afterMethod メソッドと実行されます。
次にテスト・クラスの終了時に実行される afterClass メソッドが実行されます。
次にテストの終了時に実行される afterTest メソッドが実行されます。
最後にテスト・スイートの終了時に実行される afterSuite メソッドが実行されます。


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

・・・略・・・

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

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

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

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

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

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

以下、テスト・クラスの完成形サンプルです。
ValidatorUtilityTest.java
package com.mitchy_world.testng.sample;

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

import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class ValidatorUtilityTest {
	@BeforeMethod
	public void beforeMethod() {
		System.out.println("beforeMethod");
	}

	@AfterMethod
	public void afterMethod() {
		System.out.println("afterMethod");
	}

	@BeforeClass
	public void beforeClass() {
		System.out.println("beforeClass");
	}

	@AfterClass
	public void afterClass() {
		System.out.println("afterClass");
	}

	@BeforeTest
	public void beforeTest() {
		System.out.println("beforeTest");
	}

	@AfterTest
	public void afterTest() {
		System.out.println("afterTest");
	}

	@BeforeSuite
	public void beforeSuite() {
		System.out.println("beforeSuite");
	}

	@AfterSuite
	public void afterSuite() {
		System.out.println("afterSuite");
	}

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

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

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

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

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

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

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

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

	/**
	 * {@link com.mitchy_world.testng.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 と違って TestNG ではテスト・メソッドの名前の先頭を test にする必要はありません。
本当にそれでも動作するのかを確認するため、テスト・メソッドの名前の先頭はわざと変えています。

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

テスト・スイートの作成

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

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

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

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

テスト対象クラス
ConvertorUtility.java
package com.mitchy_world.testng.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 com.mitchy_world.testng.sample;

import static org.testng.Assert.assertEquals;

import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class ConvertorUtilityTest {
	@BeforeMethod
	public void beforeMethod() {
		System.out.println("beforeMethod");
	}

	@AfterMethod
	public void afterMethod() {
		System.out.println("afterMethod");
	}

	@BeforeClass
	public void beforeClass() {
		System.out.println("beforeClass");
	}

	@AfterClass
	public void afterClass() {
		System.out.println("afterClass");
	}

	@BeforeTest
	public void beforeTest() {
		System.out.println("beforeTest");
	}

	@AfterTest
	public void afterTest() {
		System.out.println("afterTest");
	}

	@BeforeSuite
	public void beforeSuite() {
		System.out.println("beforeSuite");
	}

	@AfterSuite
	public void afterSuite() {
		System.out.println("afterSuite");
	}

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

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

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

	/**
	 * {@link com.mitchy_world.testng.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 com.mitchy_world.testng.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 com.mitchy_world.testng.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 com.mitchy_world.testng.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つのクラスが完成したら「パッケージ・エクスプローラー」は以下の図のようになっていると思います。
図:パッケージ・エクスプローラー


次にいよいよテスト・スイートの作成ですが、実はウィザードでテスト・クラスを作成した際に
testngsample.xml ができていると思います。
これを開いて ConvertorUtilityTest の内容も追記したのが以下です。
testngsample.xml
<?xml version="1.0" encoding="UTF-8"?>
<suite name="Suite" parallel="false">
  <test name="Test">
    <classes>
      <class name="com.mitchy_world.testng.sample.ConvertorUtilityTest"/>
      <class name="com.mitchy_world.testng.sample.ValidatorUtilityTest"/>
    </classes>
  </test>
</suite>

XML は
suite(テスト・スイート)
  └test(テスト)
     └class(テスト・クラス)
というツリー状の構成になっています。
suite 要素の parallel 属性を tests に、thread-count 属性を追加して値を数値にすると、
指定数値の数だけスレッドが作成されて test 要素単位でテストを平行実行させることが可能です。

他にもこの xml でテスト間の依存関係を作ったり、特定パッケージのテストだけをいっきにテストしたりと
色々な制御が可能です。
が、それなりに複雑な話になるのでここでは割愛します。

では testngsample.xml を実行してみましょう。
testngsample.xml を右クリックしてメニューから「実行」>「TestNG Suite」を選択します。
図:TestNG Suite

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

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


と、テスト・スイートについて説明しましたが、実は eclipse からの実行だと
「パッケージ・エクスプローラー」で test フォルダを右クリックして「実行」>「TestNG Test」だけでも
パッケージ以下のテストを一括実行できたりします。
ただし、この方法だとパッケージ以下の全てのテストを実行してしまうし、
スレッドでの平行実行などはできません。

細かい制御をしたければテスト・スイートを作成しましょう。

ちなみにテストを実行し終わると、test-output というフォルダとともにテスト結果が html として出力されます。

ページ1TestNGの概要〜利用準備【ユニットテスト - テスト】
ページ2TestNGの利用方法(基本編)【ユニットテスト - テスト】
ページ3TestNGの利用方法(応用編)【ユニットテスト - テスト】

ダウンロード

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

更新履歴

2011/04/10 内容見直し
2011/02/19 新規作成


TOPJavaテスト → This Page
Valid CSS!