テスティングフレームワーク保守案件の改修やると、回帰テストの漏れが原因で重大な問題が発生することが最近多くなってきました。。
そこで最近のテスティングフレームワークについて調査してみます。 INDEXJUnit4JUnitの最新版はバージョン4でアノテーションに対応されました。便利な機能が追加されたようなので、早速サンプル作って動作確認です。
package junitsample;
import static org.junit.Assert.*;
import java.util.ArrayList;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
public class JUnit4SampleTest {
public JUnit4SampleTest() {
System.out.println(System.getProperty("line.separator")
+ "JUnit4SampleTest(): コンストラクタは、各テストメソッドの前に実行される。");
}
@BeforeClass
public static void beforeClassTest() {
System.out.println("beforeClassTest(): @BeforeClassは、最初の1回だけ実行される。");
}
@AfterClass
public static void afterClassTest() {
System.out.println("afterClassTest(): @AfterClassは、最後の1回だけ実行される。");
}
@Before
public void beforeTest() {
System.out.println("beforeTest(): @Beforeは、各テストメソッドの前に実行される。");
}
@After
public void afterTest() {
System.out.println("afterTest(): @Afterは、各テストメソッドの後に実行される。");
}
@Test
public void methodA() {
System.out.println("methodA(): @Testは、テストメソッド。");
}
@Ignore
@Test
public void methodB() {
System.out.println("methodB(): @Ignoreは、テスト対象外になる。");
}
@Test(expected = IndexOutOfBoundsException.class)
public void methodC() {
System.out.println("methodC(): @Testの要素expectedで期待する例外クラスを指定する。");
ArrayList上記テストクラスを実行すると。。@Ignoreのテストメソッドでは、コンストラクタのみで、@Before、@Test、@Afterは実行されません。 beforeClassTest(): @BeforeClassは、最初の1回だけ実行される。 JUnit4SampleTest(): コンストラクタは、各テストメソッドの前に実行される。 beforeTest(): @Beforeは、各テストメソッドの前に実行される。 methodA(): @Testは、テストメソッド。 afterTest(): @Afterは、各テストメソッドの後に実行される。 JUnit4SampleTest(): コンストラクタは、各テストメソッドの前に実行される。 JUnit4SampleTest(): コンストラクタは、各テストメソッドの前に実行される。 beforeTest(): @Beforeは、各テストメソッドの前に実行される。 methodC(): @Testの要素expectedで期待する例外クラスを指定する。 afterTest(): @Afterは、各テストメソッドの後に実行される。 JUnit4SampleTest(): コンストラクタは、各テストメソッドの前に実行される。 beforeTest(): @Beforeは、各テストメソッドの前に実行される。 methodD(): @Testの要素timeoutで指定した時間(ミリ秒)でテストが終わるかテストする。 JUnit4SampleTest(): コンストラクタは、各テストメソッドの前に実行される。 beforeTest(): @Beforeは、各テストメソッドの前に実行される。 methodE(): assertXxxxxメソッドは org.junit.Assert を static importすれば使える。 afterTest(): @Afterは、各テストメソッドの後に実行される。 afterClassTest(): @AfterClassは、最後の1回だけ実行される。 以下のように@Ignoreは明示的に斜線が入って表示されています。 また、methodD()は、1000ミリ秒を越えたのでテストが失敗しています。 複数のテストクラスを一括で実行する以下のように、@RunWithと@SuiteClassesを使います。
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({JUnit4SampleTest.class, JUnit4SampleTest2.class})
public class AllTests {
}
TestNGTestNGは、JUnitとよく似ていますが、JUnit4よりもアノテーション対応を先行していました。@BeforeClassはstaticでなくてもよいので、JUnitよりも柔軟性が高いです。 あえて難点を言うと、Eclipseのテキストエディタからショートカットで実行できないくらいでしょうか^^; インストールJUnit4と違いEclipseには標準でインストールされていないので、TestNGのプラグインをEclipseの「ソフトウェア更新」でインストールしましょう。URLは、"http://beust.com/eclipse"です。 また、jarファイルをダウンロードしてクラスパスに追加する必要がありますが、maven2なら以下の設定を<dependencies>に追加すれば準備OKです。
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>5.1</version>
<classifier>jdk15</classifier>
<scope>test</scope>
</dependency>
準備ができたので、先ほどのJUnit4サンプルを元にテストコードを作ってみました。
package com.powerdee.sample.test;
import static org.testng.Assert.assertEquals;
import java.util.ArrayList;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class TestNgSampleTest1 {
public TestNgSampleTest1() {
System.out.println(System.getProperty("line.separator")
+ "TestNgSampleTest1(): コンストラクタは、最初の1回だけ実行される。");
}
@BeforeClass
public void beforeClass() {
System.out.println("beforeClassTest(): @BeforeClassは、最初の1回だけ実行される。");
}
@AfterClass
public static void afterClassTest() {
System.out.println("afterClassTest(): @AfterClassは、最後の1回だけ実行される。");
}
@BeforeMethod
public void beforeTest() {
System.out.println("beforeTest(): @Beforeは、各テストメソッドの前に実行される。");
}
@AfterMethod
public void afterTest() {
System.out.println("afterTest(): @Afterは、各テストメソッドの後に実行される。");
}
@Test(groups = { "groupA" })
public void methodA() {
System.out.println("methodA(): @Testは、テストメソッド。(groupA)");
}
@Test(expectedExceptions = IndexOutOfBoundsException.class)
public void methodB() {
System.out.println("methodB(): @Testの要素expectedExceptionsで期待する例外クラスを指定する。");
ArrayList list = new ArrayList();
System.out.println(list.get(0));
}
@Test(timeOut = 1000, invocationCount = 3, threadPoolSize = 1)
public void methodC() {
System.out.println("methodC(): @Testの要素timeOutで指定した時間(ミリ秒)でテストが終わるかテストする。");
for (int i = 0; i < 1000; i++) {}
}
@Test
public void methodD() {
System.out.println("methodD(): assertXxxxxメソッドは org.testng.Assert を static importすれば使える。");
String str = "TestNG";
assertEquals(str.charAt(5), 'G');
}
}
上記テストクラスの実行結果です。JUnit4と違い、コンストラクタは初回のみですね。。@BeforeClassなどの挙動は同じです。但し、テスト実行順序が不特定のようです。
TestNgSampleTest1(): コンストラクタは、最初の1回だけ実行される。
beforeClassTest(): @BeforeClassは、最初の1回だけ実行される。
beforeTest(): @Beforeは、各テストメソッドの前に実行される。
methodC(): @Testの要素timeOutで指定した時間(ミリ秒)でテストが終わるかテストする。
afterTest(): @Afterは、各テストメソッドの後に実行される。
beforeTest(): @Beforeは、各テストメソッドの前に実行される。
methodC(): @Testの要素timeOutで指定した時間(ミリ秒)でテストが終わるかテストする。
afterTest(): @Afterは、各テストメソッドの後に実行される。
beforeTest(): @Beforeは、各テストメソッドの前に実行される。
methodC(): @Testの要素timeOutで指定した時間(ミリ秒)でテストが終わるかテストする。
afterTest(): @Afterは、各テストメソッドの後に実行される。
beforeTest(): @Beforeは、各テストメソッドの前に実行される。
methodA(): @Testは、テストメソッド。(groupA)
afterTest(): @Afterは、各テストメソッドの後に実行される。
beforeTest(): @Beforeは、各テストメソッドの前に実行される。
methodD(): assertXxxxxメソッドは org.testng.Assert を static importすれば使える。
afterTest(): @Afterは、各テストメソッドの後に実行される。
beforeTest(): @Beforeは、各テストメソッドの前に実行される。
methodB(): @Testの要素expectedExceptionsで期待する例外クラスを指定する。
afterTest(): @Afterは、各テストメソッドの後に実行される。
afterClassTest(): @AfterClassは、最後の1回だけ実行される。
PASSED: methodC
PASSED: methodC
PASSED: methodC
PASSED: methodA
PASSED: methodD
PASSED: methodB
===============================================
com.powerdee.sample.test.TestNgSampleTest1
Tests run: 6, Failures: 0, Skips: 0
===============================================
methodCは、@Testの属性"invocationCount"でメソッド実行回数を3に設定しています。 複数のテストクラスを一括で実行する下記のテストクラスを追加して、先ほどのテストと一括に実行してみます。
package com.powerdee.sample.test;
import org.testng.annotations.Test;
public class TestNgSampleTest2 {
public TestNgSampleTest2() {
System.out.println(System.getProperty("line.separator")
+ "TestNgSampleTest2(): コンストラクタは、最初の1回だけ実行される。");
}
@Test(groups = { "groupA" })
public void methodE() {
System.out.println("methodE(): @Testは、テストメソッド。(groupA)");
}
@Test
public void methodF() {
System.out.println("methodF(): @Testは、テストメソッド。");
}
}
TestNGの場合、testng.xmlというファイルに実行方法の設定をします。 @Testのgroups属性で定義したグループのみ実行する場合は、以下のようにinculdeで指定します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="TestNgSuite" verbose="1">
<test name="TestNgSamples">
<groups>
<run>
<include name="groupA" />
</run>
</groups>
<classes>
<class name="com.powerdee.sample.test.TestNgSampleTest1"/>
<class name="com.powerdee.sample.test.TestNgSampleTest2"/>
</classes>
</test>
</suite>
あとは、パッケージエクスプローラなどから、(testng.xmlを右クリック)→(実行)→(TestNG Suite)を指定すれば実行されます。 おすすめ書籍
|