連載
» 2008年09月22日 00時00分 公開

次世代テストフレームワークでテストを変える(2):JUnitにはないTestNGの“5”つの強力なテスト用機能 (1/2)

[阪田浩一,株式会社クロノス]

 前回の記事「JUnitより簡単なオープンソースの「TestNG」とは?」では、JUnitとの比較を通じてオープンソースのJava用次世代テスティングフレームワーク「TestNG」について解説し、TestNGのEclipseプラグインをインストールしてTestNGのテストをEclipseから実行しました。

 連載の第2回である今回は、TestNG独自の機能を解説し、TestNGの魅力を紹介します。

【1】@Testアノテーションの属性

 TestNGでは、メソッドに「@Test」というアノテーションを付けることで、メソッドがテストメソッドとなります。@Testアノテーションの属性を利用してテストメソッドにさまざまな設定ができます。いくつかの属性を一覧に示します。

属性 説明
expectedExceptions Class[] テストを実行すると、発生する例外クラスを指定する。複数指定でき、その場合どれか1つの例外が発生すれば、テストは成功となる
enabled boolean テストを実行するかどうかを指定する。falseにすると、そのテストメソッドはテストとして実行されない
description String テストの説明を自由に記述する
groups String[] そのテストメソッドが所属するグループを指定する
dependsOnMethods String[] そのテストメソッドが依存するテストメソッドを指定する
dependsOnGroups String[] そのテストメソッドが依存するグループを指定する
表1 @Testアノテーションの属性

 さらに詳細な情報は、TestNG公式サイトのドキュメント(英語)を参照してください。特に注目する属性は、groupsとdependsOnXXXです。

テストを簡単にグループ分けできる「groups」属性

 groups属性には、テストが所属するグループを任意の文字列で指定します。groups属性を使うと、テストを簡単にグループ分けできます。1つのテストを複数のグループに入れることもできます。

 ブログやソーシャルブックマークでのタグ付けのようなイメージです。

テスト間の“依存”関係とは?

 そして、dependsOnXXX属性を使うと、テスト間に“依存”関係を作ることができます。属性の使い方の前に、テスト間の“依存”関係について考えてみましょう。

 例えば、データベースに接続し、SQL文を発行するSampleDaoクラスがあるとします。SampleDaoには、データベースに接続するconnect()メソッドと、実際にSQL文を発行するたくさんのselectXXX()メソッドがあります。

 次に、このSampleDaoクラスのテストを作成して、テストを実行します。もし、connect()メソッドのテストに失敗してしまうと、後のselectXXX()メソッドに対するテストはデータベースに接続する時点でエラーとなるので、必ず失敗します。このとき、「selectXXX()メソッドのテストはconnect()メソッドのテストに“依存”している」と考えます。

テスト間に依存関係を作る「dependsOnXXX」属性

 TestNGでは、dependsOnXXX属性を使うと、依存するテスト(connect()メソッドへのテスト)が失敗した場合、依存関係にあるテスト(selectXXX()へのテスト)を実行しません。実行しなかったテストは成功でも失敗でもなく、「スキップ(skip)」という状態になります。

 これは、TestNG独自の概念です。テスト結果においてすべてを失敗に含めないため、本当に失敗したのはどのテストなのか容易に把握できます。

図1 スキップした場合のテスト結果 図1 スキップした場合のテスト結果

 dependsOnMethods属性なら依存するテストメソッド名を、dependsOnGroups属性なら依存するテストのグループを指定します。基本的にdependsOnGroups属性を使用します。なぜなら、dependsOnMethods属性はテストメソッド名を直接記述するため、もし依存するテストメソッドの名称を変更すると、dependsOnMethods属性も合わせて変更する必要があるためです。テストのグループはテストメソッド名と直接関連しないため、そういった短所はありません。

TestNGやJUnitは「テスト」というものを、どのようなものととらえているか?

 TestNGではテストをカテゴリに分けてグループ化し、グループごとに依存関係を作るというのが基本的な考え方です。そして、テスト間に依存関係を作ることは「テストの実行順序」を指定することも意味します。依存するテストを先に実行する必要があるためです。

 すべてのテストが独立し、実行順序を考慮する必要がないJUnitとの大きな違いです。どちらが正しいというわけではなく、それぞれのフレームワークが「テスト」というものを、どのようなものととらえているかが表れている部分だと思います。

【2】XMLファイルでテスト対象を定義する

 JUnitでは複数のテストクラスを「テストスイート」としてまとめ、テストを一気に実行できました。TestNGでも同様に「スイート(suite)」という考え方があります。ただし、JUnitと異なる点としてプログラムからだけでなくXMLファイルからでもスイートを定義できます。XMLファイルのサンプルをリスト1に示します。

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="SampleSuite">
  <test name="SampleTest">
    <groups>
      <run>
        <include name="broken"></include>
      </run>
    </groups>
    <packages>
      <package name="sample.pack.a.*"></package>
    </packages>
    <classes>
      <class name="sample.pack.b.SampleTest"></class>
      <class name="sample.pack.c.AnotherTest">
        <methods>
          <exclude name="test.*"></exclude>
        </methods>
      </class>
    </classes>
  </test>
</suite>
リスト1 XMLファイルのサンプル

 XMLファイルは任意のファイル名を付けられます。通称「testng.xml」と呼んでいます。このXMLのルート要素は<suite>です。基本的に、スイートには1つ以上のテストがあり、テストには1つ以上のクラスがあり、クラスには1つ以上のメソッドがある、という構造です。

 ただし、<test>要素にはクラスのほか、実行するパッケージ、グループを記述できます。サンプルではsample.pack.aパッケージにあるすべてのテストクラス(サブパッケージにあるクラスも含む)と、SampleTestクラス、AnotherTestクラスをスイートとしてまとめています。

メソッドの指定に正規表現も使える

 ただし、AnotherTestクラスはメソッド名がtestで始まらないテストメソッドのみ対象とします。そして、対象となったテストのうち、実行するのは「broken」グループのテストメソッドのみです。なお、パッケージの指定にワイルドカード(*)を、メソッドの指定に正規表現を利用できます。

EclipseからXMLファイルに記述したテストを実行すると……

 XMLファイルに記述したテストを実行するときは、Eclipseであればテストクラスを実行する場合と同様に[パッケージ・エクスプローラー]でXMLファイルを選択し、右クリックから[実行]→[TestNG Suite]を選択してください。

図2 自動的に作成された「testng-failed.xml」 図2 自動的に作成された「testng-failed.xml」

 テストプログラムと実行に関する設定を分離できることで、テストのサブセットを簡単に作成できます。例えば、EclipseでTestNGのテストを実行していくつかのテストが失敗した場合、デフォルトでは失敗したテストだけを実行するXMLファイルをTestNGが自動的に作成します。

 TestNGは、テストを実行すると自動的に「test-output」ディレクトリを作成し、テストが失敗したときのみ、そのディレクトリに「testng-failed.xml」を作成します。エンジニアはテストが失敗した後プログラムを修正し、再度失敗したテストだけテストを実行したいと思うはずです。このファイルを実行すれば、失敗したテストだけを簡単に実行できます。

【3】前後処理のアノテーション

 前回の記事でも紹介しましたが、TestNGのテストクラスにおいてメソッドにJUnit 3のsetUp()/tearDown()メソッドの役割をさせるには、@BeforeMethod/@AfterMethodアノテーションを使います。TestNGには、さらにまだ@BeforeXXX/@AfterXXXアノテーションがあります。前後処理のアノテーションを一覧に示します。

アノテーション 説明
@BeforeMethod そのクラスにある各テストメソッドを呼び出す前にアノテーションを付けたメソッドを実行する
@BeforeClass そのクラスにあるあらゆるテストメソッドを呼び出す前にアノテーションを付けたメソッドを実行する
@BeforeGroups そのグループにあるあらゆるメソッドを呼び出す前にアノテーションを付けたメソッドを実行する
@BeforeTest <test>要素に含まれるあらゆるメソッドを呼び出す前にアノテーションを付けたメソッドを実行する
@BeforeSuite <suite>要素に含まれるあらゆるメソッドを呼び出す前にアノテーションを付けたメソッドを実行する
@AfterMethod そのクラスにある各テストメソッドを呼び出した後にアノテーションを付けたメソッドを実行する
@AfterClass そのクラスにあるすべてのテストメソッドを呼び出した後にアノテーションを付けたメソッドを実行する
@AfterGroups そのグループにあるすべてのテストメソッドを呼び出した後にアノテーションを付けたメソッドを実行する。複数のグループを指定した場合、各グループが終わるたびにメソッドを呼び出す
@AfterTest <test>要素に含まれるすべてのテストメソッドを呼び出した後にアノテーションを付けたメソッドを実行する
@AfterSuite <suite>要素に含まれるすべてのテストメソッドを呼び出した後にアノテーションを付けたメソッドを実行する
表2 前後処理のアノテーション

 一覧にあるように、前後処理を実行するタイミングは前述したXMLの構造と関連します。さまざまなタイミングで処理を実行できるため、初期化やクリーンアップ処理をより細かく柔軟に設定できます。TestNGの大きな魅力の1つです。

JUnit 4にも前後処理のアノテーションはある

 なお、JUnit 4にも@BeforeClass/@AfterClassアノテーションがあります。ただし、JUnit 4の場合@BeforeClass/@AfterClassを付けるメソッドはstaticメソッドである必要があります。そのため、やや使いづらい印象です。TestNGではそのような制限はありません。

 次ページでは、残りのテストメソッドにパラメータを渡す機能や簡単にテストのパターンを増やす機能について解説します。

       1|2 次のページへ

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。