*

JUnit入門その9[@RunWithアノテーションを利用したテストの作成]

公開日: : 最終更新日:2016/12/05 Java, JUnit


スポンサードリンク



今回は@RunWithアノテーションを利用したテストの作成方法を説明させていただきます。

JUnitでテストを書いていると、テスト対象メソッドの引数と戻り値の期待値だけ異なるテストメソッドが増えてきますよね。モックを利用した場合も同様の事が言えます。

このようなテストはDRYではないですし、メンテナンス性は低いと言えます。

この問題を解決するために@RunWithアノテーションが有効です。

本エントリーの内容は以下の通りです。

  1. @RunWithアノテーションとは
  2. Theories.classテストを利用したテスト
  3. Parameterized.classを利用したテスト


1 @RunWithアノテーションとは

@RunWithアノテーションを利用して、Runnerクラスを指定できます。
Runnerクラスとは、JUnitのorg.junit.runner.Runnerクラスで、どのようなテストケースを実行するかを制御するクラスとなります。

Runnerクラスの実際の実装クラスとざっくりとした説明は以下の通りです。

クラス名 説明
org.junit.runners.Suite まとめて実行させたいテストクラスの指定と実行を行う。
org.junit.experimental.categories.Categories 基本的な考え方はSuiteと同様、テスト対象のメソッドやクラスをカテゴリ付けすることで、テストスイートから実行する対象を細かく制御できるようになります。
org.junit.experimental.runners.Enclosed テストケースを分類し、グループ化出来るようになります。
org.junit.runners.Parameterized パラメータ化したリストを引数として、任意のテストメソッドを逐次的に実行したい場合に利用します。
org.junit.experimental.theories.Theories Parameterizedと似ていますが、指定したFixtureの各要素を引数として、任意のテストメソッドを逐次的に実行したい場合に利用します。

ザックリしていて全然分かりませんね・・・
org.junit.experimental.theories.Theoriesとorg.junit.runners.Parameterized
は以降で説明させていただきます。

他のクラスについては別エントリーを作成する予定です。

2 Theories.classテストを利用したテスト

一番シンプルな例

一番シンプルな例を用いて基礎知識を説明させていただきます。

これが組み合わせデータのテストを実現するための一番シンプルな例となります。

  • DataPointSampleTestクラスに@RunWith(Theories.class)を付与
  • @DataPoinを付与したStringのstaticメンバのDATA_PARAMを定義
  • @Theoryを付与したtestメソッドで引数のparamとDATA_PARAMが同じか検証

との部分がポイントとなります。ってほぼ全てですが・・・

実行すると以下のような結果になります。
一番シンプルな例の実行結果

以下利用しているクラスとアノテーションの説明となります。

Theories.class

@RunWith(Theories.class)のようにRunnerクラスとしてTheories.classを指定します。

@DataPoint

単一のテストデータに対して付与するアノテーションです。

@DataPoints

複数データに対して付与するアノテーションです。上記の例では利用してませんが・・・
後ほど説明いたします。

@Theory

実際のテストメソッドに付与するアノテーションです。

@Theoryを付与したメソッドをもう1追加した例

@Theoryを付与したメソッドをもう1追加すると以下のようになります。

test2を追加後にテストを実行すると、testとtest2がテスト対象のメソッドとして認識されました。
test2を追加後の実行結果

この様に、同じデータを他のテストでも利用することが可能となります。
(中身同じですが・・・)

複数データを利用するテストの例

テストデータが複数(Stringの配列)になりましたので、DATA_PARAMに付与するアノテーションが@DataPoints(sを追加)に変わっています。

@DataPointのままだとテストデータがStringの配列として認識されてしまい、
テストメソッドもtest(String[] param)とのシグネチャにする必要があります。

これに伴いDataPointsのインポートも必要となります。

後は、テストを通すために
testメソッドが呼び出された回数をカウントするメンバ(static intじゃないと失敗します)の追加
assertThatでの期待値の指定方法
を行っています。

テストを実行すると

がコンソールに出力されて、各要素を引数としてtestメソッドが呼び出されている事が確認できます。

ついでに@Beforeなどの動作との関係も確認してみます。

実行結果は以下のようになります。

なんも言えねー(古っ)

テストデータとテストメソッドの対応の説明

型の異なるテストデータとそれに対応するテストメソッドを定義するにはどうしたらいいのでしょうか?

各型の@DataPointsとそれに対応するテストメソッドを実装すればOKです。

以下の例には、Stringを要素とするテストデータとそれに対応するテストメソッド
intを要素とするテストデータとそれに対応するテストメソッドが含まれています。

実行結果は以下の通りです。

メソッドの引数の型に対応する@DataPointsの各要素がテストに渡されて呼び出されていることが確認できます。

テストデータにクラスを用いる例

今までは、基本データ型を用いた@DataPointsの例でしたが、今度はクラスを用いた例となります。

インナークラスのTestDataの配列を作成し、その配列に対して@DataPointsを付与しています。
それ以外は基本データ型の配列の時と同じです。

なお、TestDataはインナークラスとして定義していますが、普通のクラスとして定義しても問題ないです。

テストデータにHashMapを用いる例

先ほどの例ではインナークラスを定義して利用しましたが、わざわざこんなインナークラスを定義するほどのこともないのですよね。

何か良い方法はないでしょうか?
その答えの1つにHashMapの利用があると言えます。

HashMapの配列だと初期化時に値を定義できませんので@DataPointsはgetParametersメソッドに付与するようにしています。
これで前述のインナークラスと同じ事が実現可能です。

型の安全性: 型 HashMap[] の式は、未検査の型変換を使用して Map[] に準拠するようにする必要があります
との警告がコンパイラから出力されちゃいます。

この警告は無視するとしても、
キーがStringで値がObjectのMapですのでタイプセーフじゃなくりますのでイマイチですよね。
その点が難点ではあります。

結局早く仕上げようとなるとタイプセーフさは犠牲にするしかないのでしょうか・・・
rubyやgroovyみたいに・・・

その辺が嫌な場合はFixtureのクラスを定義して利用するべきだと言えます。

Mockを絡めた例

JMockitを利用したモックを絡めたテストの例を説明させていただきます。
JMockitの詳細につきましては「JUnit入門その3[Eclipse4.4のJUnitプラグインとMockフレームワークのJMockitの併用の基本]」をご覧ください。

まず利用するクラスの定義となります。

Person tarou = new Person(“tarou”);
Greet(tarou);
のように利用するイメージです。Personはモック化しますのでダミー実装となっております。

テストは以下のようになります。

このようにMockの振る舞いを定義するためにも@DataPointsは利用可能となります。

話は少し変わりますが、@RunWith(Theories.class)を利用すると@DataPointsの終端でない要素でテストが失敗した場合は、その時点でテストが終了します。

テストデータとテストの実装内容にもよりますが、@DataPointsの単一要素が仮想的なテストメソッドに対応するような実装の場合は途中で失敗しても、最後までテストが走って欲しいですよね。
そんな場合は@RunWith(Parameterized.class)を利用します。

3 @RunWith(Parameterized.class)を利用した例

getParametersメソッドがIterableを返却するようになり、それに伴い中身も書き換えていますが、基本的には「Mockを絡めた例」の物と本質的には同じです。

getParametersメソッドに付与するアノテーションが、@DataPointsから@Parametersに変わっています。
@ParametersがParameterized.class利用時のテストデータ指定アノテーションとなります。

@Parametersで指定された各要素を引数として、ParameterizedSampleTestのコンストラクタが呼ばれた後、@Testが付与されたtest()が呼び出されます。

@Parametersで指定している(name=”Greet.sayHello {0} is {3}”)の部分は、テスト実行時の各テストデータに対するテスト結果の表示用の文字列の指定となります。

{0}がObject[x][0]
{3}がObject[x][3]
xは任意のテストデータのインデックスとなりますので
{0}にはtarou,hanako,tomが展開されます。
{3}には10,40,25が展開されます。

実際に実行すると以下のように表示され、それぞれのテストデータに対するテストメソッドの呼び出しが個別に表示されていることが確認できます。
スクリーンショット 2015-12-05 16.19.18

コンソールには以下の情報が出力されます。

この情報からテストがどの順序で実行されるかが理解できると思います。

3件とも成功していては、途中で失敗しても全部実行されるかが確認できませんので、2件目の期待値を書き換えてみます。

以下のように2件目でテストは失敗しますが、3件とも実行されていることが分かります。
スクリーンショット 2015-12-05 16.30.49

JUnit入門その9[@RunWithアノテーションを利用したテストの作成]は以上です。


スポンサードリンク



関連記事

JDK8(java 8)の新機能のラムダ式の利用方法[その3:java8が用意している関数型インターフェース]

[その2:関数型インターフェースを例としたラムダ式] と説明させていただいておりますが、

記事を読む

Java超入門 with Eclipse[3:クラスに関する基礎知識(クラスとインスタンスとパッケージ)]

Javaといえば、「オブジェクト指向」とのイメージがとっても強いですよね。 そう、そうです。間違い

記事を読む

Eclipse4.4(Java)におけるビルド・パス関係の設定方法[ビルド・パス上のソース・フォルダー]

Eclipse4.4(Java)におけるビルド関係のビルド・パス上のソース・フォルダーの利用方法を説

記事を読む

JUnit入門その8[Eclipse4.4のJUnitプラグインのテストケースのカバレッジをEclEmmaを利用して測定してみる]

今回は「EclEmma」を使って、テストのカバレッジの測定を行うエントリーとなります。 「djUn

記事を読む

JUnit入門その4[Eclipse4.4のJUnitプラグインとDBUnitの併用(環境構築と基本)]

JUnit入門その1 JUnit入門その2[Eclipse4.4のJUnitプラグインのasse

記事を読む

JDK8(java 8)の新機能のラムダ式の利用方法[その1:概要]

「JDT betaを利用してJDK8対応のEclipse開発環境を作成する」では、「Eclipse」

記事を読む

Eclipse4.3のチュートリアル機能で”Hello World”アプリケーションの作成方法を説明する。

Eclipseのインストールが終了したので、各画面エリアの名称の説明、各画面エリアの使い方の説明を

記事を読む

お勧め本紹介[新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES)]

リファクタリング―プログラムの体質改善テクニック (Object Technology Series

記事を読む

Eclipseのインストールと日本語化とJDK8(Java8)対応[Eclipse4.4とEclipse4.3]

インストールするEclipseのバージョンですが、とりあえず4.3をターゲットとしておき、 4.4

記事を読む

Java超入門 with Eclipse[4:クラスに関する基礎知識(修飾子とクラスとインスタンスと変数)]

前回は、Javaの基本であるクラスの基本的な知識をざっくりと説明させていただいたあと、 packa

記事を読む

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Selenium入門その6[Selenium3でWebDriver(Java/Junit4)の環境を作成しEdge,Chrome,Firefoxで確認してみる]

Selenium3も3.0.1がリリースされましたし、今後は本格的にS

Selenium利用時のトラブルシューティング方法[クリック編]

Seleniumは便利なテスト自動化ツールですし、今後は更なる利用者の

Java8のラムダ式とStream APIを利用してコーディング量の削減サンプル集

Java8になりラムダ式と「Stream API」が利用できるようにな

Selenium入門その5[ページオブジェクトパターン(Page Object Design Pattern)を利用して変更に強いテストを作成する方法]

Selenium入門その2 では「UIマップファイル」と言う仕組みが

Javaによる非同期処理入門その1[非同期処理の実装方法の概説]

Javaによる非同期処理に関するエントリーを前々から作成したいと思って

→もっと見る

Optimization WordPress Plugins & Solutions by W3 EDGE
PAGE TOP ↑