SSブログ

JUnit Tips 「from JavaWorld 10月号 JUnitTips から」 [Test]

いくつか学ぶこともありましたので、備忘録の意味を含め2点纏めてみました。

  1. テストメソッドの名前に日本語の名前をつけることを検討する。

    日本語を母国語として利用しているプログラマであれば、テストで用いるクラスやメソッドの名前に名前をつけるとテストの内容がよりわかり易く表現できます。よりわかり易く表現できるのであれば、日本語の名称(クラス名、メソッド名)を付与することを検討しても よいのではという考えです。
    なんらかの副次的な問題が起こるのではと懸念してしまいますが、通常、他のプログラムからテストケースを参照することはない、つまり、テストケースクラスは他のクラスから基本的に非依存であるといえますので、クラス間の関係に起因する問題は起こりにくいと考えられます。

    ※ただし、クラス名に日本語を含めると環境(IDE, OS, ファイルシステム、 ビルドツール、各種自動化ツール、SCM)によっては正常に動作しない恐れがあるので、事前に検証をおこなうことが望ましいです。

    懸念事項も残りましたが、この考えは当職にとっては思いつきもしない斬新な考えで新たな発想に繋がりました。適用可否、他の分野への応用を一度検討、検証してみる価値はありそうです。
  2. 配列やコレクションの検証

    問題点:
     JUnitの標準で実装されているメソッドでは配列の比較はできないため、検証をおこなうには、配列の中身を1つずつ比較する必要がある。ただし、工数やコードの可読性の低下に繋がる。

    解決案:
    ThirdParty提供の検証メソッドを利用する。

    (1)JUnit-addonsのArrayAssertクラスを利用する。
     例:
      Object[] expected = ....;
      Object[] actual = ....;
      ArrayAssert.assertEquals("一致すべき", expected, actual);

    (2)コレクションAPIの利用
     格納順に依存しないかたちでListの中身を比較するには、要素の順序を持たないSetオブジェクトに格納しなおしてから比較する。
    ※ただし、同じ要素が複数個格納されている場合には、この方法では不正確な結果しか得られない。
    例:
      ArrayList expectedList = ....;
      ArrayList actualList = ....;
      assertEquals("一致すべき", new HashSet(expectedList), new HashSet(actualList));

    (3)JUnit-addons の ListAssert の利用。
     Listの要素を順不同で比較するメソッドおよび、特定の要素の存在を調べるメソッドがある。
     例:
      List expectedList = ....;
      List actualList = ....;
      ListAssert.assertEquals("一致すべき", expectedList, actualList);

    (4)GSBaseの利用
     Listの要素を順不同で比較する機能が用意されている。

    JUnit-addon, GSBase にはこの他にも様々な機能があります。
    検証用のロジックが必要になった場合は、このようなツールを流用可能か判断したうえでテストを進めるべきですね。

References


DBUnitを利用した単体テストに関して [Test]

DBを使用した単体テストをおこなう場合には、テーブルに格納するデータを変更する必要が生じます。テスト実施前のテーブルのデータに影響を与えたくない場合には、テストの方法として次の2種類の方法が考えられます。

  1. テストケース実行時にDBMSに対しコミット要求をおこない、検証時にはコミットされたデータを検証する方法。この場合には、テスト実行前にテーブルのバックアップをおこない、テスト実行後に復元をおこなう。
  2. テストケース実行時にはデータを追加・更新・削除し(コミットはおこなわない)、検証後、トランザクションをロールバックする方法

1.の方法を選択すると、テスト実行前にテストデータを投入するテーブルのバックアップをおこない、テスト終了時にバックアップからテーブルの内容を復元する必要が生じます。2. の方法を選択すると、テーブルのバックアップ・復元等、初期化、終了に伴うコストを 省略すること ができるため、1. に比べるとテストの実行時間を軽減することができます。(テストクラスごとにバックアップ・復元をおこなうのであれば、必ずしも大きな実行時間を要することはありません。)しかしながら、トランザクション制御、トランザクションスコープ、分離レベル(isolation level)によっては(1)の方法をとらざるをえない場面があるかと思います。

今回は、JUnitを基に拡張されたDBUnitを利用してどのように実現すべきか検討してます。まず 1. の方法でデータのバックアップ、復元をJUnitの前後処理でおこなう方式に関して(自分の復習を兼ねて)以下に整理してみます。最後に 2. ロールバックする方法に関しても少し整理してみます。

1. テストケース実行時にDBMSに対しコミット要求をおこない、検証時にはコミットされたデータを検証する方法

まず、テーブルのバックアップおよび復元の単位をどの単位にするかを考えてみます。テストケースごとにバックアップ、復元をおこなってもコストがかかるだけですので、必要でない限りテストケースの全体の前処理でバックアップを、後処理で復元をおこなうよう必要があります。次に実現方法に関して検討してみます。

実現方式としては、以下の2通りの方式を選択できます。

  1. TestNGの@Configurationタグを利用
  2. TestSetupクラスの利用。

1.TestNGの@Configurationタグを利用

TestNGを利用すれば、@Configurationアノテーションで、テストケースタグに含まれる全てのテストクラスの前後で実施される動作を定義できます。2のTestSetupクラスを使用した方式でも同様のことが実現できますが、よりスマートに記述できますし、suiteメソッドがstaticである制約を回避するよう設計されています。

 @Configuration(beforeTest = true)
 @Configuration(afterTest = true)

@Configuration(beforeTest = true)
 public void oneTimeSetup() {
  //System.out.println("テストケース全体の前処理");
 }

@Configuration(beforeTest = true, afterTest = true)
 public void aroundTest() {
  //System.out.println("テストケース全体の前後でおこなう処理");
 }

2.TestSetupクラスの利用。

古典的な方法は、TestSetupクラスでテストスイートの前後で実施する処理を定義する方式です。TestCaseのサブクラス(もちろんTestSuiteでも構いません)でsuiteクラスメソッドをオーバライドし、その中でTestSuiteインスタンスを作ってからTestSetupインスタンスでラップします。(デコレーターパターン)TestSetupクラスでは、setUpメソッドを定義しテストスイートごとの前後に実施したい処理を記述します。ただしsuiteメソッドはstaticメソッドでなければならない制約がありますので、TestNGを採用できるのであれば(他にもメリットがありますので)、TestNGを選択することをお勧めします。

 public class SampleTest extends TestCase {

  static void oneTimeSetup() throws Exception {
   //バックアップ処理
  }

  static void oneTimeSetup() throws Exception {
   //バックアップしたデータの復元
  }

  //static メソッドでなければならない制約が難点です。
  public static Test suite() throws Exception {

   TestSuite suite = new TestSuite(SampleTest.class);

   TestSetup wrapper = new TestSetup(suite) {
    public void setUp() throws Exception {
     oneTimeSetup();
    }
    public void tearDown() throws Exception {
     oneTimeTearDown();
    }
   };
        return wrapper;
  }
 }

○DbUnitを用いたバックアップ処理と復元処理に関して

DBUnitには指定したテーブルの内容をファイルにエクスポートする機能およびその逆のインポートの機能があります。(具体的には下記のコードをご覧ください。)

テーブルの内容のバックアップに関しては、oneTimeSetupメソッドをご覧ください。本メソッドでは、バックアップ対象のテーブルが指定されていれば、データセットに対して追加を行い、内容をファイルに出力しています。oneTimeTearDownメソッドでは、バックアップされたファイルを基に、DBMSの内容を更新します。

トランザクションスコープに関しては、用途に応じて選択されてください。観点としては、バックアップ処理と復元処理それぞれのトランザクションをテストケースと別々にするかどうかです。(下記の例では、1つのコネクションでバックアップ、テストケースの実行、データの復元をおこなっています。)

/**
     * <p>事前処理</p>
     *
     * @throws Exception JavaNative例外
     */
    protected void oneTimeSetUp() throws Exception {

        try {
   //コネクションの取得
   conn_ = getJdbcConnection();
   
   //DBUnit用コネクションの取得
   iConn_ = new DatabaseConnection(conn_);

   //データのバックアップ
   if (getBackupTables() != null) {
    QueryDataSet partialDataSet = new QueryDataSet(iConn_);
    //バックアップ対象のテーブルを指定
    for (int i=0; i < getBackupTables().length; i++) {
     partialDataSet.addTable(getBackupTables()[i]);
    }
    //ファイルのバックアップ
    backupFile_ = File.createTempFile("BACKUP", ".xml");
    //System.out.println(backupFile_.toString());
    FlatXmlDataSet.write(partialDataSet, new FileOutputStream(backupFile_));
   }
  } catch(Exception e) {
   e.printStackTrace();
  } finally {
   //closeIDatabaseConnection(iConn_);
  }
    }
   
    /**
     * <p>事後処理</p>
     *
     * @throws Exception JavaNative例外
     */
    protected void oneTimeTearDown() throws Exception {
      try {
    //コネクションの取得
    //conn_ = getJdbcConnection();
       
    //DBUnit用コネクションの取得
    //iConn_ = new DatabaseConnection(conn_);
       
       if (getBackupTables() != null) {
     //バックアップしたデータでテーブルの内容を復元する。
     IDataSet dataSet = new  FlatXmlDataSet(backupFile_);
     DatabaseOperation.CLEAN_INSERT.execute(iConn_, dataSet);

     //バックアップファイルの削除
     backupFile_.deleteOnExit();
       }
  } catch(Exception e) {
   e.printStackTrace();
  } finally {
   //コネクションのクローズ
   closeIDatabaseConnection(iConn_);
  }
 }

 /** <p>バックアップ対象のテーブル</p>
   * サブクラスで実装。
   */
 protected String[] getBackupTables() {
  return new String[]{"TBL1", "TBL2", "TBL3"};
 }

2.テストケース実行時にはデータを追加・更新・削除し(コミットはおこなわない)、検証後、トランザクションをロールバックする方法

 テスト検証後にトランザクションをロールバックする方法に関して考察してみます。この方式を採用すると、テストケースによりテーブルの変更をおこなえる上、ロールバックによりテーブルのバックアップ・復元の工程を省くことが可能になります。ロールバックする単位に関しては、テストケースごとにテーブルに変更した内容を無効にしたいので、テストケースごとにロールバックすることになります。

具体的には以下のとおりです。まず、setUp時に、コネクションの取得後、オートコミットを無効化し、テストデータを投入します。次に、テストケースを実行し、DBの内容が想定どおりに変更されているかを検証します。最後に、tearDown時に、ロールバックをおこなうことにより、テーブルをテスト実行前の内容に戻します。

DBを利用した単体テストをおこなう際に、テスト実行前の状態を復元できることは重要です。必要な場合には、以上の方法を選択子の1つとして検討してみてはいかがでしょうか?


WSADへのTestNG Eclipse pluginの導入 [Test]

WSADへのTestNG Eclipse pluginの導入

→依存するEclipse Pluginファイルが存在しないため、インストールできない模様です。

WSAD5.1.2 に TestNG の Eclipse Plugin の導入を試みましたが、エラーが発生しました。原因を突き止めるため、Eclipse Plugin の定義ファイルを確認したところ、依存関係にあるプラグインがWSADには含まれていないことを確認できました。(該当のファイルは、Eclipse3.0, Eclipse3.1 には含まれている。)

Eclipse 3.0, Eclipse3.1 はサポートするが(検証済み)、Eclipse2.xはもうサポートしないということですかね?詳しいことがわかればまた整理してみたいと思います。


TestNG Features List [Test]

■はじめに

しばらく使ってなかったので、バージョンアップに伴い機能を復習してみます。

TOC

  • TestNGの特徴
  • テストスイートの実行
  • テストケースの前後処理の設定
  • 例外のチェック
  • ファクトリ
  • JUnitテストケースの変換
  • References

■TestNGの特徴

  • アノテーションベースのテストケース
        - JSR 175 のアノテーションを利用したテストケース(JDK5.0の場合)
        - JDK 1.4の場合はJavadoc アノテーションとしてテストケースを記述可能
  • 柔軟なテストの設定
        - setUp, tearDown の実行単位を制御可能(スイート、テストクラス、テストメソッドの単位)
  • テストケースのカテゴライズ
        - メソッドグループ
        - グループのグループ
        - 部分的にグループを混在(クラスレベルとメソッドレベルのグループの混在)
        - 包含と排他
        - テストケースの無効化 
  • テストケースに対するパラメータ渡しを可能に
  • ファクトリ(動的に(パラメータを生成し)テストを生成することを可能に)
  • テストケースの依存関係を定義可能に
  • antとの統合
  • マルチスレッドテストおよびタイムアウトの定義
  • 繰り返し実行
  • 失敗したテストのみを再実行可能
  • TestNG から JUnit Test を実行可能
  • JUnit テストケースを TestNGテストケースに変換可能
  • プログラムからTestNGを呼び出し可能
  • ロギング
  • 他の開発ツールとの親和性
        - Eclipse Plugin
        - Maven Plugin (開発中?)
  • JDK 1.4 and 1.5 で動作します。
■テストスイートの実行

TestNGでテストスイートは以下のようにXMLで定義されます。

 
   
    
      
    
  

グループを指定して実行することも可能です。

  
    
      
    
  
  
    
  

■テストケースの前後処理の設定

JUnitでは、各テストメソッドの開始前後に実行する定型処理を定義することができました。定型処理の場所を他の場所に配置したい場合には、テストケースのベースクラスや、 template method pattern を用いプログラミングする必要がありました。

TestNGでは、アノテーションにより定型処理の場所を定義することができます。以下のように、定型処理の場所をより柔軟に選択することが可能です。また、複数のメソッドを前後処理として定義することも可能です。

○テストスイートタグに含まれる全てのクラスの実行前後で実施される動作

  • @Configuration(beforeSuite = true)
  • @Configuration(afterSuite = true)
○テストケースタグに含まれる全てのテストクラスの前後で実施される動作
  • @Configuration(beforeTest = true)
  • @Configuration(afterTest = true)
○テストクラスが全てのテストメソッドの開始前に1回、全てのテストメソッドの終了後に1回実施される。
  • @Configuration(beforeTestClass = true)
  • @Configuration(afterTestClass = true)
○指定した全てのテストメソッドの前後で毎回実施される。
  • @Configuration(beforeTestMethod = true)
  • @Configuration(afterTestMethod = true)

■例外のチェック

TestNGでは、期待される例外をアノテーションを用いて検証します。下のテストケースの場合では、テストケース実行時に NumberFormatException が throw されることを期待しています。

public class  NumberUtilsTest {
	@Test(groups = {"tests.math"})
	@ExpectedExceptions(NumberFormatException.class)
	public void test() {
		NumberUtils.createDouble("12.23.45");
		assert false;  //shouldn't be invoked
	}
}

私見になりますが、どの例外クラスがthrowされるかを検証するだけでよければ、このアノテーションが利用できますが、テストケースの結果、throw される例外クラスの状態を検証する必要があるならば、例外クラスを catch し、例外クラスの状態を検証する必要があると考えられます。よって、アノテーションが利用できるケースは制限された範囲になると考えております。

■ファクトリ

ファクトリは、テストを動的に生成することを可能とします。以下がファクトリの例です。WebTestに与えられたパラメータを10, 20, 30...と増加させた場合、テストケースにどのような影響を及ぼすかを検証しています。

public class WebTestFactory {
  @Factory
  public Object[] createInstances() {
    Object[] result = new Object[10];
    for (int i = 1; i < 10; i++) {
      result[i] = new WebTest(i * 10); 
    }
    return result;
  }
}

ファクトリメソッドは、@Test, @Configuration のようなパラメータを受け取り、 Object[]を返す必要があります。オブジェクトは、どんなクラスをも返却することができます。そして、TestNG annotation を含む必要もありません。

public class WebTest {
  private int m_numberOfTimes;

  public WebTest(int numberOfTimes) {
    m_numberOfTimes = numberOfTimes;
  }

  @Test
  public void testServer() {
    for (int i = 0; i < m_numberOfTimes; i++) {
      // access the web page
    }
  }
}

test.xml には、factory method を含むクラスに対する参照を持てばよいだけです。テストクラス自身のインスタンスは実行時に生成されます。


■JUnitテストケースの変換

JUnit のテストケースクラスをTestNGのテストケースに変換するorg.testng.JUnitConverterクラスを用意しています。以下のようなオプションを用意しています。

  • 出力形式:JDK1.4(javadoc annotation)、JDK5.0(JDK5.0 annotation)
  • 元のソースを上書きするか?

antのサンプルは以下のとおりです。


	
	 
	
 
	
	 
	

■References


EasyMock & EasyMock ClassExtension [Test]

■はじめに

  • EasyMockもJDK5.0に対応されたみたいなので、変更点を含め検証してみます。


■EasyMock & EasyMock ClassExtension 概要

JUnitは、テストケースの実行前後の状態の変化の検証をおこなうテストスタイルです。これに対し、EasyMock は、モックオブジェクトを組み合わせることにより、テストケースを実行することにより期待されるインタラクションも検証することを実現できます。

EasyMock は、Java Proxy メカニズムを利用し、インターフェイスに対するモックオブジェクトを動的に生成します。EasyMockはテストケースの実行結果、期待される動作(expectation)を設定するために、記録/再現(record/replay)のメタファを使用します。

まず、モックを生成したいオブジェクトのそれぞれに対してコントロールオブジェクトとモックオブジェクトを生成します。モックは代理となるオブジェクトのインターフェースを満たし、コントロールオブジェクトは追加機能を提供します。メソッド呼び出し時に期待される結果を設定するには、モックに予期される引数を指定することにより実現します。戻り値が必要であれば、この後にコントロールを呼び出すことになります。期待される結果の設定を終えたら、コントロールのreplayを呼び出します。この時点でモックは記録(recording)を完了してメインオブジェクトに応答する準備が整います。最後に、コントロールのverify()を呼び出すことにより、想定どおりの動作をするかを検証することができます。
(参考:Mocks Aren't Stubs http://www.martinfowler.com/articles/mocksArentStubs.html#UsingEasymock

EasyMockは、具体的には以下のような特徴を持ちます。
詳細はEasyMockのドキュメントをご覧ください。

  • モックオブジェクトを作成する必要はありません。動的に生成します。
  • 想定される戻り値、例外を設定できます。
  • 同一のメソッド呼出に対する結果を変更することが可能です。
  • 呼び出し回数を検証することができます。
  • メソッド呼出のディフォルト値を設定可能です。
  • メソッド呼出の順序を検証可能です。

EasyMock は、指定したインターフェイス(!)を持つモックオブジェクトを生成しますが、拡張ツール(EasyMock ClassExtension)を導入することにより、指定したクラス(!)のインターフェイスを持つモックオブジェクトを生成することが可能になります。

■サンプルコード

EasyMockのZIPファイルには、テストケースのサンプルが同梱されています。このサンプルに関して、以下で少し説明してみます。

テスト対象のクラスは、JDK5.0に対応していることを確認できます。addListenerメソッドでは、setter injection pattern を用い、ClassUnderTestから呼び出されるクラスをセットします。リリース用のコードでは、Collaboratorインターフェイスを持つ実際の実装クラスをセットし、テストケースクラスでは、代理のモックオブジェクトを渡すことになります。(ExampleTest16行目)

public class ClassUnderTest {

    private Set<Collaborator> listeners = new HashSet<Collaborator>();
private Map<String, byte[]> documents = new HashMap<String, byte[]>();
    public void addListener(Collaborator listener) {
        listeners.add(listener);
    }

・・・・・

下記はテスト対象のクラスが使用するCollaboratorインターフェイスです。このインターフェイスを元にモックオブジェクトを生成します。

public interface Collaborator {
    void documentAdded(String title);
    void documentChanged(String title);
    void documentRemoved(String title);
    byte voteForRemoval(String title);
    byte voteForRemovals(String[] title);
}

EasyMockを使用したテストケースクラスは、以下のとおりです。
まず、setUpメソッドで、モックを生成し、テスト対象のクラスがモックを利用できるようセットします。
テストケースメソッドでは、テストケースの実行に伴い期待される動作を設定します。次に、モックコントール対しreplayメソッドを呼び出し、テストケースを実行可能状態に変更します。そして、テストケースを実行後、モックコントロールに対し verifyメソッドを呼び出します。これで、テストケースが想定どおりの動作をするかを検証することができます。もちろん、JUnit のassertionメソッドでテストケースの実行結果想定どおりの状態変化が得られたか検証することができます。

public class ExampleTest extends TestCase {

    private ClassUnderTest classUnderTest;
    private MockControl control;
    private Collaborator mock;

    protected void setUp() {
        //上記のCollaboratorインターフェイスを指定し、モックコントローラとして生成します。
        control = MockControl.createControl(Collaborator.class);
        //モックオブジェクトをコントローラから取得します
        mock = (Collaborator) control.getMock();
        //テスト対象のクラスを生成します。
        classUnderTest = new ClassUnderTest();
        //テスト対象のクラスが実際のクラスの代替としてモックオブジェクトを使用
        //できるように、テスト対象のクラスに生成したモックオブジェクトをセットします。
        classUnderTest.addListener(mock);
    }

	・・・・・

    public void testVoteForRemoval() {
        //テストケースの実行結果、期待される動作を宣言します。
        //"Document"が追加されることを期待することを宣言します。
        mock.documentAdded("Document");
        //期待される戻り値を宣言します。
        control.expectAndReturn(mock.voteForRemoval("Document"), 42);
        //モックのdocumentRemovedメソッドが呼び出されることを期待することを宣言します。
        mock.documentRemoved("Document");

        //設定状態から呼び出し可能状態に変更します。
        control.replay();
        //テストケースを実行します。
        classUnderTest.addDocument("Document", new byte[0]);
        //JUnitを用い、テストケースの実行結果を検証します。
        assertTrue(classUnderTest.removeDocument("Document"));
        //呼び出し可能状態から検証可能状態に戻します。
        control.verify();
    }
}

本バージョンでは、JDK5.0に対応されましたが、基本的な文法は変わりませんね。バージョンアップに伴う詳細な変更点を確認していきましょう。

■EasyMock 1.2RC2に関する変更点(since1.1) 2つのバージョンを提供

  • JDK1.3以降に対応
  • JDK5.0に対応
 両方のバージョンに関する変更点
  • order of arguments for ArgumentsMatcher is like in EasyMock 1.0 now
  • stack traces are now only cut if the exception is thrown from EasyMock
  • convenience methods expectAndDefaultReturn() and expectAndDefaultThrow() allow setting default return values and throwables in one line of code
  • hashCode() implementation is changed for better performance
  • added Clover coverage reports
○JDK5.0向けの新機能
  • support for VarArgs
  • type safety: expectAndReturn() and expectAndDefaultReturn() for Objects now check whether the given return value is applicable. Trying control.expectAndReturn(mock.getString(), new Object())
        will now generate an error at compile time instead of runtime.  
  • MockControl uses generics now, the mock object needs not to be casted anymore

■EasyMock ClassExtension の使用方法に関して

指定したクラスのモックオブジェクトを生成するには、 モックオブジェクトの生成の際に、org.easymock.MockControl の代わりに org.easymock.classextension.MockClassControl を使用してください。ソースコードは以下のようになります。上がインターフェイスを指定してモックオブジェクトを生成する例で、下がクラスを指定してモックオブジェクトを生成する例となります。

control = MockControl.createControl(CollaboratorInterface.class);
       ↓
control = MockClassControl.createControl(CollaboratorClass.class);

■Easymock class extenstion Requirements

The EasyMock class extension requires Java 1.3.1 or above, Easymock 1.2, JUnit 3.8.1, cglib 2.1.0 (2.0.x also works but cannot mock a class without visible constructor) and asm (use the version that matches your cglib version, you can also use cglib-nodep-2.1 which includes asm)

■References


主要なテストフレームワークの比較 [Test]

主要なテストフレームワークの比較(http://www.theserverside.com/articles/content/TestFrameworkComparison/article.html)

JUnit4.0の話題もちらほら聞こえる今日この頃です。記事を拝見させて頂き、少し纏めてみます。

全体的な所感

JUnit4.0, JTiger, TestNG、それぞれアプローチや細かい点に関しては異なる点もありますが、GOALは同じ方向であるように感じました。JUnitの制約から解放し、JDK1.5の機能(特にアノテーション)を利用した機能拡張が主な特徴であるように見受けられます。具体的には、いずれのテストフレームワークも以下の機能を実現しています。JUnit4.0の開発も開始されましたし、今後益々の発展を遂げてくれるかと思います。いずれのゴールに向かおうとも、我々開発者のテストに力を貸してくれるものと期待しています。

  • annotationの導入
  • クラス構造の制約から解放:クラスjunit.framework.TestCaseを継承する必要はない。
  • メソッド名の制約から解放:テストメソッド名は"test"から始まる文字列でなくとも構わない。"setUp","tearDown"というメソッド名の縛りも不要になる。
  • 特定のテストを無視させることができるようになる。
  • テストケースのカテゴライズ
  • static assertion method の導入(TestCaseクラスを継承する必要はない)

詳細は以下に纏めてみます。

比較対象のテストフレームワーク

JTiger

JDK1.5の機能に影響を受けて開発されたアノテーションに基づくテストフレームワーク

特徴

  • annotationやstatic imports
    ※static imports は必ずしも必要ではない。可読性を向上させるため。
  • テスト実行するために外部の設定ファイルを必要としない。
  • JUnitのように ant による実行が可能。

annotation

Annotation

Description

@Test

defines a test case to be executed

@Category

Specifies the category (or categories) to which the test belongs. Can be attached to a method or class declaration

@Ignore

Tells JTiger to ignore the test

@SetUp

Defines the set up method to be used for the tests

@TearDown

Defines the tear down method to be used for the tests

@ExpectException

Tells JTiger to expect exceptions to be thrown from the test. This takes the class definition of the expected exception with an optional boolean to allow subclasses or not. This removes the need for things like this:

	  try {
	shouldFail();
	fail();
} catch (SomeException e) {
	// success
}

@Repeat

Tell JTiger to repeat the test n times. Each run will have a distinct result and if n is less than 0, then 1 is used for n.

@Fixture

Used to document the fixture class with more useful names and descriptions.

assertion

  • JTiger は多くのassertion機能を提供します。詳細は以下のパッケージをご覧ください。(pacakge org.jtiger.assertion)

Test Results

  • JTigerのテスト結果には、以下の6つの異なる種類があります。 
    " Success ," " Ignored (Annotated), " " Ignored (Cannot Invoke), "   " Failure (Set Up), " " Failure, " " Failure (Tear Down) ." " Success "
  • test method の結果は void 以外も返却可能となります。void以外を返却する場合、返却されたオブジェクトに対してtoString()された文字列が出力されます。

 ■TestNG

JTigerと非常によく似た機能を実現しています。

  • テストケースのカテゴライズに関して
    the lack of @Category that JTiger uses. TestNG, instead, defines groups in the @Test annotation.
    TestNG also supports groups of groups with the following syntax: @Test(groups = {"group1", "group2"}).
  • テストケースの有効化・無効化
    Notice, also, the enabled = false. This provides the same functionality the same as the @Ignore JTiger provides.
     However, one big difference is that disabled tests will not be displayed in the report so that any disabled tests run the risk of getting lost. 
  • テストケースの適用範囲の制御
    @Test can be applied to methods as well as classes. When applied to the class, all public methods on the class are considered to be test cases. 
  • 繰り返し実行
    Like JTiger, TestNG tests can be repeated with @repeat(invocationCount=10).
  • テストに対する依存関係の定義
    TestNG also has the idea of dependencies on tests.
     The syntax for these dependencies is @Test(dependsOnMethods={"method1, method2"}) and @Test(dependsOnGroups={"group1, init.*"}).
     If these dependencies fail, the dependent methods are marked as skipped.
     This reduces the number of failures seen on the reports due to upstream failures and helps to highlight the actual error. 
  • テストケースに対するパラメータの受け渡しに関して
    Unlike JUnit and JTiger, TestNG methods can take parameters.
     @Parameters({"param1", "param2"}) defines the parameters param1 and param2.
     Values for these parameters are defined in the XML configuration file we'll see in a later section. 
  • 設定
    Using @Configuration, a developer can specify exactly when a method executes during a test run

■JUnit4

the goal of JUnit 4 is to "encourage more developers to write tests by simplifying JUnit."

主な特徴

  • IDE integration improvements
  • move to static assert methods like JTiger and TestNG use.
  • move to an annotation  based system.
    Set up and tear down will be handled with @Before and @After
    Shared set up is handled with @BeforeClass and @AfterClass
    @Ignore like JTiger
  • Test methods in JUnit 4 will no longer be required to start with test
  • The @Test annotation will support expected exceptions.(e.g. @Test(expected=NullPointerException.class))
  • JUnit 4 will introduce test ordering and prioritization as well as categorization and filtering.
  • JUnit 4 will also provide "forward compatibility" for current test runners 
  • a new assert: assertEquals(Object[], Object[]) as well as support Java's assert and AssertionError 
  • remove the distinction between failures and errors. 
  • a new package structure: org.junit . 
  • native logging support

Here is the list of available annotations provided by TestNG:

Annotation

Description

@Test

defines a test case to be executed

@Configuration

Configuration information for a TestNG class. Provides facilities for grouping and parameters.

@ExpectedExceptions

Like the JTiger annotation, tells TestNG to expect certain exceptions. Takes an array of class definitions.

@Factory

Factory annotation

 References


テストすべきかどうか? [Test]

by J. B. Rainsberger(JUnit FAQ)

「一般的な考え方は次の通りです。それ自体で壊れないのであれば、(簡単過ぎるので)壊れることはありません。第一の例はgetX()メソッドです。getX()メソッドが、インスタンス変数の値のみを答える、と考えてください。その場合getX()は、コンパイラー、あるいはインタープリターが一緒に壊れない限り、壊れることはありません。ですから、getX()をテストすべきではありません。何の利点も無いのです。setX()についても同じことが言えますが、そのsetX()メソッドが、パラメーターに関して何らかの妥当性検証を行う場合や、何らかの副作用がある場合には、恐らくテストする必要があるでしょう。」

 


この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。