*

JUnit入門その3[Eclipse4.4のJUnitプラグインとMockフレームワークのJMockitの併用の基本]

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


スポンサードリンク



JUnit入門その3ではMockフレームワークのJMockitを利用したテスト環境の構築と使い方について記載させていただきます。
次エントリーでより実線的な利用例の説明をさせていただこうと考えております。

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

  1. Mockフレームワークがユニット(単体)テストに必要な理由
  2. JMockitの概要と環境の構築方法の説明
  3. JMockitの使い方の説明

 

1 Mockフレームワークがユニット(単体)テストに必要な理由

スタブとドライバとMockオブジェクトの違い

まずは、ドライバとスタブとMockオブジェクトの違いを明確にさせていただきます。

各用語の説明に用いる基本のシーケンス図は以下の通りです。
シーケンス図1
スクリーンショット 2014-10-25 18.18.59

見たまんまですが、クラスAからクラスBのメソッド1を呼び出し、クラスBからクラスCのメソッド2とメソッド3を呼び出しています。

ドライバの説明

呼び出し先の任意のクラスの任意のメソッドをテストするための専用クラスをドライバと言います。

シーケンス図1を例にするとクラスAの変わりに、クラスBのメソッド1を呼び出すためのテスト用クラスを作成する。
これがドライバです。
スクリーンショット 2014-10-25 18.34.43

スタブの説明

任意のクラスが依存するクラスをテスト用クラスに置き換えるとします。このテスト用クラスをスタブと言います。

シーケンス図1を例にするとクラスCの代わりのテスト用クラスを作成して、クラスBからこのテスト用クラスのメソッド2、メソッド3を呼び出します。
スクリーンショット 2014-10-25 18.53.46

Mockオブジェクトの説明

シーケンス図の観点からは、スタブとMockオブジェクトは同じになります。
スクリーンショット 2014-10-25 19.01.25

スタブは、呼び出しに対してオブジェクトを返却したり、決められた振る舞いだけをするクラスです。
Mockオブジェクトは、スタブとは異なりテスト対象クラス(シーケンス図の例ではクラスB)からの呼ばれ方に着目しています。
例えば、メソッドの呼び出しの回数や順番、引数の値等をテストします。
Mockオブジェクトが期待する振る舞いでない場合はテストが失敗します。

Mockフレームワークが必要な理由

DBに格納されているデータや外部システムが返却するデータはテストを実行するたびに異なる可能性があります。
これについては、任意のテストを実行する前にDBに格納されているデータや、外部システムが保持しているデータを常に同じにする事で回避可能ですが、
DAO(Data Access Object)にバグが潜んでいることも考えられます。外部システムも同様です。
スクリーンショット 2014-10-26 17.54.16

テスト対象クラスは決まっているはずなのに、現在のテスト対象ではないDAOのテストを実装するのはおかしな話ですし、DAOのテストはDAOのテストクラスで実装すべきです。
スクリーンショット 2014-10-26 18.44.49

このようにテストを行いたいクラス(ロジック)を明確にして、再現性の高い(必ず同じ結果が得られる)テストケースを作成するためにMockオブジェクトは必要不可欠です。

またTDD(Test Driven Development)を行う場合は、テスト対象のクラスの依存クラスが全て作成できていることはほとんどありませんので、この観点からもMockオブジェクトの利用は必要不可欠と言えます。

2 JMockitの概要と環境の構築方法の説明

Javaで利用可能なMockフレームワークとして結構な数のプロダクトが存在します。
JMockit、JMock、Mockito、EasyMockが有名であると言えます。

この中でも最近ではJMockitがもっとも利用されています。
JMockitが利用されている理由として、以下の特徴があげられると言えます.

JMockitの特徴

  • モック化する対象の型はインターフェースを実装していなくてもOK
  • モック化するメソッドはfinal、static、privateでもOK
  • コンストラクタの呼び出しもモック化することが可能
  • モックオブジェクトをテスト対象クラスに動的に注入したり、パラメーター経由で引き渡さなくてもOK
  • クラスの一部の振る舞いだけをモック化することが可能

上記の特徴の通りですが、JMockitは利用する上で制約が少ないMockフレームワークであると言えます。

JMockitのダウンロード

Getting started with the JMockit toolkitにブラウザでアクセスします。すると以下の画面が表示されますので、赤枠部分をクリックしjmockit-libs.zipをダウンロードします。
スクリーンショット 2014-10-26 19.18.15

2014年10月26日現在の最新バージョンのファイルはjmockit-1.12.zipとなっています。
ダウンロードしたzipを解凍するとjmockit-1.12フォルダが生成されます。

JMockitをEclipseで利用するための準備

JMockitの動作確認用のプロジェクトの作成

プロジェクト名:JmockitSampleでJavaプロジェクトを作成します。

libフォルダの作成と必要なjarをコピー

プロジェクト直下にlibフォルダを作成します。
スクリーンショット 2014-10-26 19.45.13

スクリーンショット 2014-10-26 19.47.19

作成したlibフォルダにjmockit1.orgフォルダ配下の「jmockit.jar」と「jmockit-coverage.jar」をドラッグ&ドロップします。
スクリーンショット 2014-10-26 19.51.49

すると以下の画面が表示されますので、何も変更せずに「OK」ボタンをクリックします。
スクリーンショット 2014-10-26 19.53.33

プロジェクトのビルド設定の実施

JmockitSampleプロジェクトのルートを選択した状態で右クリックメニューの「プロパティ」をクリックします。
スクリーンショット 2014-10-26 19.59.50

プロパティ画面が表示されますので、左側の「Javaのビルド・パス」を選択後に右側のタブ「ライブラリ」をクリックします。
スクリーンショット 2014-10-26 20.03.01

「jar追加…」ボタンをクリックします。
スクリーンショット 2014-10-26 20.03.01

「JARの選択」画面で先ほど追加した「jmockit-coverage.jar」と「jmockit.jar」を選択し「OK」ボタンをクリックします。
スクリーンショット 2014-10-26 21.19.10

次にJUnitのjarをビルドパスに追加します。

「ライブラリーの追加…」ボタンをクリックします。
スクリーンショット 2014-10-26 20.03.01

「ライブラリーの追加」画面が表示されますので、「JUnit」を選択し「次へ>」をクリックします。
スクリーンショット 2014-10-26 21.33.28

画面が以下のように変わりますので、JUnitライブラリー・バージョンでJUnit4が選択されていることを確認し、「完了」ボタンをクリックします。
スクリーンショット 2014-10-26 21.36.50

上記の説明の順番でビルド・パスを変更していただいたのであれば問題ないのですが、
jmockit.jarはJUnitのjarファイルより先に読み込まれるようにビルド・パスに追加する必要がありますのでご注意ください
スクリーンショット 2014-10-26 21.40.40

jmockit.jarよりJUnitが読み込まれる設定の場合以下のようなエラーが発生します。

3 JMockitの使い方の説明

JMockitはとても柔軟なモックフレームワークです。全てを説明する事も必要かも知れませんが、それでは余計に分かりにくくなると思いますので、良く利用する機能とその利用例を説明させていただきます。

説明に利用するクラスの作成

それぞれの説明の前に説明に利用するクラスを作成しておきます。
Hogeクラス、FooクラスおよびHogeクラスのテストクラスを作成します。

Hogeクラスの作成

srcフォルダを選択し、右クリックメニューを表示し[新規]>[クラス]をクリックします。
スクリーンショット 2014-10-27 15.37.52

「新規Javaクラス」画面が表示されますので
パッケージ:sample.jmockit
名前:Hoge
を指定して「完了」ボタンをクリックします。
スクリーンショット 2014-10-27 15.32.51

作成されたクラスをエディタで開いて以下のように変更してください。

Fooクラスの作成

同様の手順でFooクラスも作成してください。
といってもパッケージ・エクスプローラでsample.jmockitを選択して「新規Javaクラス」画面を表示すると、表示時にパッケージにsample.jmockitがセットされますのでこちらの操作の方がオススメです。

Hogeクラスのテストクラスの作成

パッケージ・エクスプローラでHoo.javaを選択し、右クリックメニューを表示し[新規]>[JUnit・テストケース]をクリックします。

「新規JUnitテスト・ケース」画面が表示されます。
色々オプションが指定可能ですし、「次へ」ボタンを押すとテスト対象クラスの任意のメソッドに対するテストメソッドのテンプレートを生成することも可能ですが、今回は何も変更せずに「完了」ボタンをクリックします。
スクリーンショット 2014-10-27 17.56.52

上記の3クラスを用いてJMockitの使い方を説明させていただきます。

モック化する方法

オブジェクトをモック化する方法は2種類です。

  1. テストクラスのインスタンスメンバーとしてモック化したいクラスを宣言し、@Mockedアノテーションを付与する。
  2. テストメソッドの引数に@Mocked + モック化したいクラス + 引数名を定義する。

1つめの方法のサンプル

1つめの方法のサンプルは以下のようになります。

ソース内のコメントにも記載していますが、
インスタンスメンバとしてHogeの変数を@Mockedを付与して宣言していることで、1つめのテストメソッド内のHogeクラスのインスタンスがモック化されます。
なおインスタンス変数名の変数名はhogeでなくても同じ結果になります。

モックオブジェクトにも関わらず、振る舞いを指定しない場合は戻り値の型のデフォルト値が返却されます。
この例の場合はStringを返却するmethodAなのでnullが返却されます。

あとこれは本エントリーには関係ないのですが、Eclipseのコンソールに以下のメッセージが赤文字で表示されます。
とりあえずテストは成功するので今回のエントリーでは無視します。
objc[1624]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.

スクリーンショット 2014-10-27 21.26.20

次にインスタンスメンバhogeをそのまま利用したテストを追加してみます。

assertThatで検証している内容は同じです。このことからインスタンスメンバhogeもモック化されていることが分かります。

2つめの方法のサンプル

2つめの方法のサンプルは以下のようになります。なお以下の例はからはパッケージ宣言とimport文はHogeTestクラスと同様ですので省略しています。

「test_引数でアットマークMocked」メソッド内でのみHogeクラスはモック化されます。
試しに引数なしのテストメソッドを追加してテストを実行してみます。

実行すると失敗しました。スタックとレースの最上部は以下の通りです。
文字列”hoge”が返却されていることから普通のHogeクラスのインスタンスであることが分かります。

テスト実行時の画面
スクリーンショット 2014-10-27 21.50.56

振る舞いを記録する方法

モックオブジェクトに振る舞いを記録してみます。一般的なモックフレームワークは振る舞いを記録すれば、その振る舞いと異なる呼び出しがモックオブジェクトに対して行われるとテストは失敗します。しかしJmockitはその振る舞いのチェックを厳密にも、ゆるゆるにもすることが可能です。

振る舞いを定義し厳密にチェックする方法

Expectationsを利用します。
もっともシンプルなExpectations例は以下の通りです。

当然ですが、assertThatの第一引数をhoge.methodA(“hoge”)に変えるとテストは失敗します。

複数メソッドの振る舞いの記録例は以下の通りです。

前述のテストの2行のassertThatの順番を入れ替えると当然テストは失敗します。

画面イメージでは分かりにくいですがmethodAが引数”hoge”を指定して呼び出されることが期待されていたにも関わらず予期しない呼び出しがされたと障害とレースに表示されています。
スクリーンショット 2014-10-28 13.16.24

Expectationsの最後の例として、モックの戻り値を指定する方法のサンプルを記載させていただきます。

振る舞いを記録し厳密にチェックしない方法

NonStrictExpectationsを利用します。テスト用のコードの記載方法はExpectationsと同じです。
HogeTestの全てのExpectationsをNonStrictExpectationsに置換してNonStrictExpectationsがどのように動作するか確認してみます。

置換後のHogeTestは以下のようになりました。

テストを実行すると全てのテストが成功しました。
スクリーンショット 2014-10-28 16.30.44

現在のHogeTestクラスに含まれるテストはモックに対して呼び出すメソッドの順番を記録しているだけなので
NonStrictExpectationsに書き換えると全て成功してしまいます。

NonStrictExpectationsでは、Expectationsとは異なり、指定した通りにメソッドが実行されなくても、テストは成功します。
NonStrictExpectationsの用途としては、スタブを作成したいときに利用すると便利です。

NonStrictExpectationsでも失敗するテストを追加してみます。
引数が存在するmethodAの動作を2つ記録(引数も戻り値も異なる)させて、assertThatの検証で間違った戻り値を期待値とする検証を書いてみます。

実行すると当然失敗します。1つ目のassertThatで失敗しているので2つ記録した意味が無かったですね・・・
スクリーンショット 2014-10-28 16.56.41

障害トレースは以下の通りです。
java.lang.AssertionError:
Expected: is “失敗するような戻り値”
but: was “引数2の時の戻り値”

NonStrictExpectationsの説明の最後にスタブ的な利用方法について記載させていただきます。

・引数ありのmethodAにどんな文字列が渡されても”スタブの戻り値”を返却する例

コードのコメントにも記載していますが動作を記録させる時の引数としてanyStringというオブジェクトを指定すると、どんな文字列が引数の場合でもとの動作を記録することが可能です。

anyString以外にも引数のマッチング方法として以下の物が利用可能です。
引数がプリミティブ型の場合はanyInt、anyBooleanなとを指定します。

実際のテストでのモックオブジェクトの利用方法

Jmockitの基本的な利用方法については、ここまでの説明で普通に利用できるレベルまではご理解いただけたと思います。
このまでのサンプルではテストメソッドから直接モックオブジェクトを呼び出していましたが、実際のテストではテスト対象クラスの裏側にいるオブジェクトをモック化し、テストメソッドから呼び出すのはテスト対象クラスのメソッドだけです。

今扱っているクラスで実際のシーケンス図のイメージを表現すると以下のようになります。
スクリーンショット 2014-10-28 19.01.37

このような処理となるテストを実際に実装してみます。

Fooクラスの変更

FooクラスにmethodBとmethodCを追加しました。

Hogeクラスの変更

privateなインスタンスメンバにStringのnameとFoo型のfooを追加しました。
引数なしmethodAをなくして、引数ありmethodAの内容を変更しました。

これでHogeをテスト対象クラス、Fooをモックオブジェクトとしてテストが実装できるようになりました。

HogeTestでHogeクラスのmethodAをテストを実装

まずはHogeをテスト対象クラスとし、Hogeクラスのテストが実行される時に、Hogeクラスのインスタンスメンバのfooがモックオブジェクトになるようにクラスを変更します。

まずは、思った通りにhoge.fooがモックオブジェクトになっているかを確認するテストを書いてみます。

テストを実行すると成功しました。思った通りモックオブジェクトとなっています。
スクリーンショット 2014-10-28 21.28.58

次はいよいよHogeクラスのmethodAメソッドのテストを書いてみます。
HogeクラスのmethodAメソッドの中身を見るとテストのバリエーションとして以下の2つがあげられると思います。

  • 引数にintの範囲の数値の文字列を指定
  • 引数に数値でない文字列を指定

・引数にintの範囲の数値の文字列を指定するテストの実装
追加したテストメソッドは以下の通りです。

このテストも成功しました。
スクリーンショット 2014-10-28 21.34.58

・引数に数値でない文字列を指定
methodAに渡す引数とassertThatの期待値以外は先ほどのテストメソッドとほぼ同じです。
(対応する振る舞いの記録も異なります。)
追加したテストメソッドは以下の通りです。

このテストも成功しました。
スクリーンショット 2014-10-28 21.48.44

「test_methodAに引数に数値でない文字列を指定したとき」のコードからでは分かりにくいですが、Expectationsで動作を記録していますのでfoo.methodCは呼び出されていないことが保証されます。

「JUnit入門その3[Eclipse4.4のJUnitプラグインとMockフレームワークのJMockitの併用の基本]」は以上です。

「JUnitプラグインと関連プロダクトの利用方法」エントリー(まとめメージ)を作成いたしましたので、こちらも是非ごらんください。


スポンサードリンク



関連記事

Eclipseの「JSDT-jQuery」プラグインでJQuery(JavaScript)のコード補完が可能な環境を作成する

Eclipse for JavaEE Developer等のWeb開発系のEclipseがインストー

記事を読む

JUnit入門その6[Eclipse4.4のJUnitプラグインとDBUnitの併用(便利に利用するためのユーティリティの作成)]

JUnit入門その4 でDBUnitの環境構築を説明させていただきました。 今回は、前提値デ

記事を読む

Java超入門 with Eclipse[5:クラスに関する基礎知識(メソッドをJUnitを使って説明)]

クラスに関する基礎知識シリーズも、いよいよメソッドを残すのみとなりました。 前回までは、Eclip

記事を読む

Java超入門 with Eclipse[2:プリミティブ型(基本データ型)とは]

他のプログラミング言語と同様に、Javaにもデータ型が存在します。 Java超入門の第2回では、プ

記事を読む

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

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

記事を読む

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

Seleniumは便利なテスト自動化ツールですし、今後は更なる利用者の増加が見込まれます。 とは言

記事を読む

Eclipseの使い方(Eclipse4.4のブックマーク機能とタスク機能)

今回は、Eclipseのブックマーク機能とタスク機能の説明をさせていただきます。 両機能とも効率的

記事を読む

Eclipseの「DBViewer」プラグインを利用して「Java DB」の環境を作成し、SQLを発行してみる

EclipseのJUnitプラグインとDBUnitを併用したDB(データベース)のアクセス処理のユニ

記事を読む

利用すると生産性が格段に向上する厳選Eclipseショートカット集

今回のエントリーは、利用すると生産性が格段に向上するEclipseのショートカット集となります。

記事を読む

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

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

記事を読む

Comment

  1. […] ipse4.4のJUnitプラグインとMockフレームワークのJMockitの併用の基本] http://javaworld.helpfulness.jp/post-48/ […]

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 ↑