本エントリーは、EclipseのJUnitプラグインの入門的な内容を取り扱います。
利用する環境の作成につきましては、「Eclipseの使い方(Windows環境のEclipse4.3)」の「JDK8とEclipseのインストール」をご覧ください。
本エントリーの内容は以下の通りです。
- JUnitとは
- JUnitプラグインの機能説明
- JUnitプラグインの基本的な使い方
1 JUnitとは
JUnitとは、Javaで開発されたプログラムにおいてユニット(単体)テストの自動化を行うためのフレームワークと、
関連するツール群の総称です。
JUnitの目的とする理念は以下の通りです。
- 一度作成すればすばやくテストが実行可能である。
- ユニットテストが成功することで、既存機能が正常に動作していることを担保でき、バグ訂正が容易となる。
- テストコードを見れば仕様が一目瞭然となる。
- 誰でも同じテスト(ユニット)を行えるようになる。
- 修正毎に、独自のテストコードによるテスト作成、もしくはデバッガを使った手作業のテストの手間を省ける。
とはいえ、現実はそんなに簡単にはいかないです。例えば4番目の項目、テストの再現性ですが結構難しいんですよね、
Aさんが実行したら成功するのに、Bさんが実行したら失敗するや、マルチスレッドの考慮不足で、特定マシンでは成功するが、他のマシンでは失敗する等いろいろ考慮しないといけない点はあります。
JUnit standalone runner
テストクラスやテストスイートを指定して、スタンドアローンで動作するツールです。
日本にアジャイルや「JUnit」のユニットテストが導入され始めたころはスタンドアローン版を利用する事が一般的でした。
今日では、Eclipseをインストールすると「JUnit」が利用できますので、敢えてスタンドアローン版を利用することは無くなりました。
Javaコードに対するテストフレームワークとしてのJUnit
「Jenkins」や「Apache Continuum」のような継続的インテグレーションツールでも「JUnit」のフレームワークを利用してテストの自動化がはかられています。
継続的インテグレーションツールを簡単に説明すると、昼休みが12:00から始まる会社であれば、12:10分ぐらいから
GitやSubversionのようなソース管理システムからソースコードをチェックアウトし、コンパイル、ユニットテストの実行を行うような仕組みを提供する物です。
定期的に、アプリケーション自体のソースコードのコンパイルが通るか、ユニットテストは大丈夫か等を検証してくれるので、問題点の発覚を早くし、傷口が小さい時点で気付かせてくれることに大きな意義があります。
EclipseのJUnitプラグイン
昔のEclipseはJUnitプラグインが標準ではインストールされていませんでしたので、各自でインストールする必要がありましたが、
Eclipse 4.3 Standardには「JUnit4.11」が標準ではインストールされています。
どのバージョンからそうなのかは不明ですが、「JUnit」と言えばEclipseのJUnitプラグインを指している可能性がかなり高いです。
EclipseのJUnitプラグインにつきましては、詳細な説明を後述させていただきます。
2 JUnitプラグインの機能説明
JUnit4からはアノテーションを利用してテストクラス等の認識をJUnitが行うようになりました。
今回は、アノテーションとテストケースの作成メソッドのうち、必要最低限の物を説明させていただきます。
JUnit4で利用するアノテーション
JUnit4.11で利用可能なアノテーションは結構多くありますが、本エントリーでは基本的なアノテーションのみ説明いたします。
基本的なアノテーション
基本的なアノテーションは以下の通りです。ほぼこのアノテーションだけでテストを作成できます。
| アノテーション | 説明 |
|---|---|
| @BeforeClass | テストクラスのstaticイニシャライザの後に呼ばれる。 |
| @Before | テストクラスのコンストラクタの後に呼ばれる。 |
| @Test | テストメソッドに付与 |
| @After | テストメソッド実行後に実行したいメソッドに付与 |
| @AfterClass | テストクラス実行後に実行したいメソッドに付与 |
基本的なアノテーションの実行順序
基本的なアノテーションの実行順序を以下の図に示します。
といってもファイナライザはGCの管理するところなので、呼ばれない時の方が多いです。
テストケースの作成用メソッド
Eclipseからテストクラスを作成すると、作成したクラスに
|
1 |
import static org.junit.Assert.*; |
の記述が追加されます。これによってorg.junit.Assertクラスのメソッドを自クラスのメソッドのように呼び出せます。
org.junit.Assertクラスの基本的なメソッドは以下の通りです。
具体的な利用方法は「3 JUnitプラグインの基本的な使い方」で説明させていただきます。
なおassertThatメソッドにつきましては、「JUnit入門その2[EclipseのJUnitプラグインのassertThat(org.hamcrest.CoreMatchers)の使い方]」をご参照ください。
| メソッド | 説明 |
|---|---|
| assertEquals(Object expected, Object actual) | expectedtとactualが同じ値の場合は成功、異なる場合は失敗する。 |
| assertEquals(String message, Object expected, Object actual) | expectedtとactualが同じ値の場合は成功、異なる場合は失敗し、messageが表示される。 |
| assertSame(Object expected, Object actual) | expectedtとactualが同じオブジェクトを参照している場合は成功、異なる場合は失敗する。 |
| assertSame(String message, Object expected, Object actual) | expectedtとactualが同じオブジェクトを参照している場合は成功、異なる場合は失敗し、messageが表示される。 |
| fail() | テストを失敗させたい時に利用する。 |
| fail(message) | テストを失敗させたい時に利用する。失敗した時はmessageが表示される。 |
| assertTrue(boolean) | 値がtrueの場合は成功、falseの場合派失敗する。 |
| assertTrue(String message, boolean) | 値がtrueの場合は成功、falseの場合派失敗し、messageが表示される。 |
| @Test(expected=Exception.class) | テストメソッドではないが、テストを実行すると任意の例外が発生することを期待する情報を@Testアノテーションに記載する。 |
3 JUnitプラグインの基本的な使い方
検証用のプロジェクト作成、テストクラスの作成、アノテーションの動作確認、テストケースの作成
との順番で基本的な使い方を説明させていただきます。
検証用のプロジェクト作成
Eclipseのメニューの[新規]>[Javaプロジェクト]をクリックします。
表示された画面で、プロジェクト名に「JUnitSample」と入力し「完了」ボタンをクリックします。
テストクラスの作成
テストクラスの新規作成方法は何種類か方法がありますが、今回は一番シンプルな方法で行きます。
Eclipseのメニューの[新規]>[JUnit テスト・ケース]をクリックします。
表示された画面で、名前に「TestSample」と入力し「完了」ボタンをクリックします。
次に、JUnitライブラリの追加確認画面が表示されますので、何も変更せずに「OK」ボタンをクリックしてください。
JUnit テスト・ケースが作成されました。
アノテーションで説明させていただいたアノテーションが付与されていますね。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class TestSample { @BeforeClass public static void setUpBeforeClass() throws Exception { } @AfterClass public static void tearDownAfterClass() throws Exception { } @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void test() { fail("まだ実装されていません"); } } |
各アノテーションの動作確認
各アノテーションの動作する順番を確認するために
- TestSampleのコンストラクタ
- staticイニシャライザ
- インスタンスイニシャライザ
- ファイナライザ
- 各メソッド、イニシャライザを識別するためのSystem.out.printlnの出力を追加
を追加しました、あともう1つ、テストメソッドの名前をtestSample1に変更しました。
変更後のコードは以下のようになりました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class TestSample { static { System.out.println("スタティックイニシャライザ call"); } { System.out.println("インスタンスイニシャライザ call"); } public TestSample() { System.out.println("コンストラクタ call"); } @Override protected void finalize() throws Throwable { System.out.println("finalize call"); try { super.finalize(); }catch(Exception e) { } }; @BeforeClass public static void setUpBeforeClass() throws Exception { System.out.println("@BeforeClass call"); } @AfterClass public static void tearDownAfterClass() throws Exception { System.out.println("@AfterClass call"); } @Before public void setUp() throws Exception { System.out.println("@Before call"); } @After public void tearDown() throws Exception { System.out.println("@After call"); } @Test public void testSample1() { System.out.println("@Test testSample1 call"); } } |
いよいよテストの実行です。テストの実行方法も何通りかあるのですが、
「パッケージ・エクスプローラー」で「TestSample.java」を選択後に、右クリックメニューの[実行]>[1 JUnit Test()]をクリックします。
テストが実行され、コンソールには以下のような結果が表示されました。
|
1 2 3 4 5 6 7 8 |
スタティックイニシャライザ call @BeforeClass call インスタンスイニシャライザ call コンストラクタ call @Before call @Test testSample1 call @After call @AfterClass call |
うん、予想どうりです。ってfinalize callが出力されてません。
まあファイナライザはGCに制御されているので出力されない方が多いので正しい結果です。
テストメソッドが単一だったので、いまいちな検証です。
もう1つテストメソッドを追加して実行してみます。
追加したテストは以下のとおりです。
|
1 2 3 4 |
@Test public void testSample2() { System.out.println("@Test testSample2 call"); } |
再度テストを実行しました。今度はコンソールには以下のように表示されました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
スタティックイニシャライザ call @BeforeClass call インスタンスイニシャライザ call コンストラクタ call @Before call @Test testSample1 call @After call インスタンスイニシャライザ call コンストラクタ call @Before call @Test testSample2 call @After call @AfterClass call |
今度はいい感じの結果が得られました。
アノテーションを付与されたメソッドの動作タイミング、インスタンスの生成タイミング、テストの実行タイミングが理解できました。
というか、予想通りですが・・・
簡単なテストを実装
テスト対象のクラスとしてPersonクラスを作成します。
PersonにはwalkとrunとgetNameメソッドが存在します。
(これから作るのですが・・・)
コンストラクタはPerson(int perMinWalk, int perMinRun, String name)とします。
テストファーストで行きます。
testSample1メソッド内に
|
1 |
Person person = new Person(2, 6, "太郎"); |
当然ですが、エラーとなります。
Eclipseのエラー修正機能でPersonクラスを定義します。
画面表示は以下のように変化しますので、赤枠部分の「クラス’Person’を作成します」をダブルクリックします。
すると、Javaクラスの作成ウイザードが開始しますので、何も変更せずに完了ボタンをクリックします。
空っぽのPersonクラスが作成されました。ぜんぜんエラーの修正になっとらん!
と思いつつ、本来作成してほしかったPersonクラスのコンストラクタを実装します。
コンストラクタだけ実装したPersonクラスは以下のようになりました。
|
1 2 3 4 5 6 7 |
public class Person { public Person(int perMinWalk, int perMinRun, String name){ this.perMinWalk = perMinWalk; this.perMinRun = perMinRun; this.name = name; } } |
当然ですが、this.perMinWalk、this.perMinRun、this.nameが存在しないとのコンパイルエラーが出力されています。
今度こそEclipseのエラー修正機能で、これらのインスタンス変数を作成してもらいましょう!
「Person型のフィールド’perMinWalk’を作成します」をクリックします。
予測どおりに以下のコードが追加されました。
private int perMinWalk;
他の2つも同じように操作した結果、Personクラスは以下のようになりました。
|
1 2 3 4 5 6 7 8 9 10 11 |
public class Person { private int perMinWalk; private int perMinRun; private String name; public Person(int perMinWalk, int perMinRun, String name){ this.perMinWalk = perMinWalk; this.perMinRun = perMinRun; this.name = name; } } |
残りはwalk、run、getNameメソッドですなのですが、長くなってきたのでwalkだけ実装します。
walkは引数のmin×perMinWalkをリターンするメソッドです。
testSample1メソッドでインスタンス化したpersonに対してwalkメソッドを呼び出し
その結果をassertEqualsの第二引数にセットします。
第一引数は2×walkメソッドの引数とします。
testSample1メソッドは以下のようになりました。
|
1 2 3 4 5 6 |
public void testSample1() { System.out.println("@Test testSample1 call"); Person person = new Person(2, 6, "太郎"); int min = 100; assertEquals(2*min, person.walk(min)); } |
またまたpersonにwalkメソッドがないと言われますので、エラー修正機能でwalkメソッドを作成します。
以下の画像の赤枠部分のwalkメソッドを作成するをクリックします。
生成されたwalkメソッドを以下のように修正します。
|
1 2 3 |
public int walk(int min) { return perMinWalk*min; } |
これでtestSample1は成功するはずです。実際にtestSample1だけを実行してみます。
testSample1を選択し右クリックメニューの[実行]>[1 JUnit Test]をクリックします。
テストも成功しています。
成功する例だけでは面白くないですので、testSample2メソッドは失敗するようにします。
assertEqualsもメッセージを指定できるメソッドを利用するようにしています。
|
1 2 3 4 5 6 |
public void testSample2() { System.out.println("@Test testSample2 call"); Person person = new Person(2, 6, "太郎"); int min = 100; assertEquals("person.walkがおかしいよ!", 5*min, person.walk(min)); } |
testSample2を実行してみました。
当然失敗しました。
スタックとレースの1行目は以下の通りです。
java.lang.AssertionError: person.walkがおかしいよ! expected: but was:
person.walk(100)の結果は200のところを、わざと500に変えているので納得できる結果ですね。
assertEqualsに指定したメッセージも出力されることが確認できました。
例外発生を期待するテスト
最後に、例外が発生することを期待するテストケースを追加&実行確認をして終わりにしたいと思います。
testSample3テストメソッドを追加し、Personのrunメソッドが常にArithmeticExceptionをスローするようにし
person.runがArithmeticExceptionをスローした時にテストが成功するようにします。
Personのrunメソッドは以下のとおりです。
|
1 2 3 |
public int run(int min) { throw new ArithmeticException(); } |
testSample3をとりあえず以下のようにして、テストを実行してみます。
|
1 2 3 4 5 6 7 |
@Test public void testSample3() { System.out.println("@Test testSample3 call"); Person person = new Person(2, 6, "太郎"); int min = 100; assertEquals("person.runがおかしいよ!", 5*min, person.run(min)); } |
予想どうりテストはjava.lang.ArithmeticExceptionで失敗しました。
testSample3を以下のように修正しました。
|
1 2 3 4 5 6 7 8 9 10 11 |
@Test public void testSample3() { System.out.println("@Test testSample3 call"); Person person = new Person(2, 6, "太郎"); int min = 100; try { assertEquals("person.runがおかしいよ!", 5*min, person.run(min)); fail("ArithmeticExceptionが発生するはず"); }catch(ArithmeticException e) { } } |
personのrunメソッドを呼び出した時のArithmeticExceptionをキャッチし成功
もしArithmeticExceptionが飛んでこなければ、次行で失敗するようにfail(String message)メソッドの呼び出しを追加しています。
まあこの方法でも良いのですが、もっときれいな方法があります。
それは、@Testアノテーションにスローされる例外のクラスを記述する方法です。
testSample3を以下のように修正しました。ポイントは@Test(expected=ArithmeticException.class)です。
|
1 2 3 4 5 6 7 |
@Test(expected=ArithmeticException.class) public void testSample3() { System.out.println("@Test testSample3 call"); Person person = new Person(2, 6, "太郎"); int min = 100; assertEquals("person.runがおかしいよ!", 5*min, person.run(min)); } |
実行してみたところ、成功しました。
こちらの方がtestSample3メソッドのテスト項目が明確になるといえます。
「JUnit入門その1[EclipseのJUnitプラグインの基本的な使い方]」は以上です。
「JUnitプラグインと関連プロダクトの利用方法」エントリー(まとめメージ)を作成いたしましたので、こちらも是非ごらんください。
関連記事
-
-
「HyperSQL」の環境を作成し、Eclipseの「DBViewer」プラグインを利用してSQLを発行してみる
Eclipseの「DBViewer」プラグインを利用して「Java DB」の環境を作成し、SQLを発
-
-
java8(JDK8)の新機能をEclipseとJUnitで[インターフェースのデフォルト実装の使い方]
本エントリーでは、まずSAM Typeの説明をさせていただきます。 その流れの中で「java8の新
-
-
Eclipse4.4,4.3の使い方[エディタのフォントサイズの変更方法]
今回は、Eclipse4.4と,4.3におけるエディタエリアのフォントサイズの変更方法を説明させてい
-
-
Eclipseのインストールと日本語化とJDK8(Java8)対応[Eclipse4.4とEclipse4.3]
インストールするEclipseのバージョンですが、とりあえず4.3をターゲットとしておき、 4.4
-
-
Mac(OS X)におけるJava8(jdk8)等のインストール、アップデート、アンインストール方法
Windowsとは異なりMac(OS X)ではJDKの管理(インストール、アンインストール)が難しい
-
-
Java超入門 with Eclipse[3:クラスに関する基礎知識(クラスとインスタンスとパッケージ)]
Javaといえば、「オブジェクト指向」とのイメージがとっても強いですよね。 そう、そうです。間違い
-
-
JUnit入門その3[Eclipse4.4のJUnitプラグインとMockフレームワークのJMockitの併用の基本]
JUnit入門その3ではMockフレームワークのJMockitを利用したテスト環境の構築と使い方につ
-
-
Eclipse4.4(Java)におけるビルド・パス関係の設定方法[ビルド・クラスパスの順序およびエクスポート設定]
Eclipse4.4(Java)におけるビルド関係のビルド・パス上の「ビルド・クラスパスの順序および
-
-
java8(JDK8)の新機能[大幅に強化されたコレクションAPI:java.util.List] をeclipseとJUnitで確認する。
Java8(JDK8)では、ラムダ式の導入を前提とした、コレクションAPIの新機能が追加されました。
-
-
Java超入門 with Eclipse[5:クラスに関する基礎知識(メソッドをJUnitを使って説明)]
クラスに関する基礎知識シリーズも、いよいよメソッドを残すのみとなりました。 前回までは、Eclip