ここからは、TestNGを利用したテストを作成しましょう。まず、リスト1はテストの対象となるTargetクラスです。足し算をする単純なメソッドadd()と例外を発生させるメソッドthrowException()を定義します。
public class Target { public int add(int a, int b) { return a + b; } public void throwException() { throw new RuntimeException("例外が発生しました"); } }
リスト2はTargetクラスを検証するテストクラスです。
import static org.testng.Assert.assertEquals; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class TestNGSample { private Target target; public TestNGSample() { System.out.println( "★TestNGSampleのコンストラクタを呼び出した★"); } @Test public void verifyAdd1() { System.out.println("★★★verifyAdd1()を呼び出した★★★"); int result = target.add(1, 2); assertEquals(result, 3); } @Test public void verifyAdd2() { System.out.println("★★★verifyAdd2()を呼び出した★★★"); int result = target.add(3, 3); assertEquals(result, 6); } @BeforeMethod public void init() { System.out.println("★★init()を呼び出した★★"); target = new Target(); } @Test(expectedExceptions = { java.lang.RuntimeException.class }) public void exceptionTest() { System.out.println( "★★★exceptionTest()を呼び出した★★★"); target.throwException(); } }
このTestNGSampleがTestNGのテストクラスです。テストクラスは何らかのクラスを継承する必要はありません。テストクラスにはテストメソッドを3つ定義しました。verifyAdd1()とverifyAdd2()、exceptionTest()です。
TestNGではテストメソッドに@Testアノテーションを付けます。メソッド名はtestで始める必要はなく、任意の名前を付けられます。
注目はexceptionTest()メソッドです。テストとして例外が発生するかどうかを検証する場合、@Testの属性expectedExceptionsに発生する例外クラスを指定します。テストを実行したときに、指定した例外が発生すればテストは成功、発生しなければテストは失敗となります。JUnit 3の例外テストと比較しても、意図が明確でコード量も少なくなっています。
もう1つ、@BeforeMethodアノテーションを付けたinit()メソッドを定義しました。これはテストメソッドではありません。BeforeMethodという英語の意味どおり、テストメソッドを実行する前に呼び出したいメソッドには@BeforeMethodを付けます。JUnit 3のsetUp()メソッドと同じ働きです。テストメソッドと同様、任意のメソッド名を付けられます。
また、JUnit 3のtearDown()と同じことを実現する場合は@AfterMethodアノテーションを付けます。TestNGには@BeforeXXX、@AfterXXXというアノテーションがほかにもいくつかあります。それらについては、次回詳しく解説します。
このテストを実行すると、以下のように出力されます。テストメソッドの前にinit()メソッドを呼び出していることが分かります。
★TestNGSampleのコンストラクタを呼び出した★ ★★init()を呼び出した★★ ★★★verifyAdd2()を呼び出した★★★ ★★init()を呼び出した★★ ★★★exceptionTest()を呼び出した★★★ ★★init()を呼び出した★★ ★★★verifyAdd1()を呼び出した★★★
なお、テストの実行については、この記事の最後でEclipseプラグインの導入と併せて解説します。
では、同じアノテーションベースのテスティングフレームワークであるJUnit 4とTestNGのテストを比較してみましょう。先ほどのテストをJUnit 4で記述すると、以下のようになります。
import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; public class JUnit4Sample { public JUnit4Sample() { System.out.println( "★JUnit 4Sampleのコンストラクタを呼び出した★"); } private Target target; @Test public void verifyAdd1() { System.out.println("★★★verifyAdd1()を呼び出した★★★"); assertEquals(target.add(1, 2), 3); } @Test public void verifyAdd2() { System.out.println("★★★verifyAdd2()を呼び出した★★★"); assertEquals(target.add(3, 3), 6); } @Before public void init() { System.out.println("★★init()メソッドを呼び出した★★"); target = new Target(); } @Test(expected = java.lang.RuntimeException.class) public void exceptionTest() { System.out.println( "★★exceptionTest()メソッドを呼び出した★★"); target.throwException(); } }
TestNGのテストクラスと非常に似ています。@BeforeMethodが@Beforeに、@TestのexpectedExceptions属性がexpected属性に名前が変わっている以外に違いはありません。役割も同じです。
ただし、同じ@TestでもJUnit 4とTestNGでは別のアノテーションクラスであることに注意してください(import文に注目してください)。
JUnit 4とTestNGのアノテーションが似ている理由は、JUnit 4がTestNGより後に開発されたため、TestNGに影響を受けているからです。逆に考えると、エンジニアがJUnit 4からより機能の多いTestNGへ移行することも容易であるといえます。さて、このテストを実行すると、以下のように出力されます(※注:実行する場合、JUnit公式サイトから配布アーカイブをダウンロードしてクラスパスに追加してください)。
★JUnit 4Sampleのコンストラクタを呼び出した★ ★★init()メソッドを呼び出した★★ ★★★verifyAdd1()を呼び出した★★★ ★JUnit 4Sampleのコンストラクタを呼び出した★ ★★init()メソッドを呼び出した★★ ★★★verifyAdd2()を呼び出した★★★ ★JUnit 4Sampleのコンストラクタを呼び出した★ ★★init()メソッドを呼び出した★★ ★★exceptionTest()メソッドを呼び出した★★
TestNGの出力結果と見比べてください。大きな違いが1点あります。
TestNGはコンストラクタを1回しか呼び出していませんが、JUnit 4では3回呼び出しています。JUnit 3の問題点でも説明したとおり、JUnitはテストメソッドに対してインスタンスを1つ生成します。これは、JUnit 4でもJUnit 3でも同様です。TestNGはインスタンスを1つしか作らず、テスト間で状態を共有します。
次ページでは、TestNGのEclipseプラグインのインストールについて説明し、次回についてお話します。
Copyright © ITmedia, Inc. All Rights Reserved.