JUnitは、Javaで開発された
プログラムのふるまいを
検証する為のフレームワーク、
関連するツール群の総称になります。
ユニットテストとは、コードの一部(ユニット)の
ふるまいを検証するためのテストを意味します。
ユニットのサイズは決まっていません。
ユニットを「システムの中で何らかの
有益なふるまいを行う小さなコード」
であると定義します。
JUnitの目的とする理念
- 何らかの機能のコーディングが完了し、期待通りにふるまうかどうかを確認したい場合
- コードへの変更内容を記録し、自分や他の開発者が変更の意図を理解できるようにしたい場合
- システムのふるまいについて理解したい場合
- 他者によるコードが期待通りに機能しなくなった際に、それがいつからなのか知りたい場合
最も重要なことは、
良いユニットテストを行えば自信を持って
実運用向けのシステムを
リリースできるという点です。
いわゆる単体テストが完璧であれば、
その後の結合テストによる
バグの可能性も低いと考えられる為、
JUnitテストは大きな開発プロジェクトで
あればあるほど重宝されています。
JUnit4で使用される基本的なアノテーション
1 2 3 4 5 |
@BeforeClass "テストクラスのstaticイニシャライザの後に呼ばれる" @Before "テストクラスのコンストラクタの後に呼ばれる" @Test "テストメソッドに付与" @After "テストメソッド実行後に実行したいメソッドに付与" @AfterClass "テストクラス実行後に実行したいメソッドに付与" |
JUnit4で使用される基本的なAssertクラス
Eclipseからテストクラスを作成するとJunit.Assertクラスがインポートされます。
1 |
import static org.junit.Assert.*; |
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 |
assertArrayEquals(arrays expected, arrays actual) →"配列同士を比較、イコールである場合true" assertEquals(Object expected, Object actual) →"オブジェクト同士を比較、イコールである場合true" assertFalse(boolean condition) →"条件がfalseである事を検証、falseの場合true" assertNotNull(Object obj) →"オブジェクトがNullで無いことを検証、Nullでない場合true" assertNotSame(Object expected, Object actual) →"expected != actualの場合true" assertNull(Object obj) →"オブジェクトがNullである事を検証、Nullの場合true" assertSame(Object expected, Object actual) →"expected == actualの場合true" assertTrue(boolean condition) →"条件がtrueである事を検証、trueの場合true" assertThat([value], [matcher statement]) →"汎用的な比較を許可するアサーションメソッド" fail() →"常に失敗させる。『ここに来たらアウト(テスト失敗)』箇所に配置" |
どのようなテスト観点かによって
使用するメソッドが違ってきます。
上記に記載してあるメソッドを覚えておけば
まず困ることはないでしょう。
ちなみにJUnitで
使用頻度が高いメソッドが
assertEquals()です。
ここから簡潔な方法で説明していきます。
まずテストを行いたいソースの
別フォルダーをテスト用として作成します。
今回はtestを作成しました。
1.テストを行いたいクラスで右クリック。
[新規]>[その他]をクリック。
2.JUnitテスト・ケースを選択し、
[次へ]をクリック。
3.[参照]を押下後、フォルダーはtestを選択。
テスト元クラスを確認後、[完了]をクリック。
4.testフォルダー内に
CarTestクラスが作成されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package homeSE7; import static org.junit.Assert.*; import org.junit.Test; public class CarTest { @Test public void test() { fail("まだ実装されていません"); } } |
上記の方法だと
テストクラスのメソッドには自動的に
@Testがつく状態になります。
では実際にCarTestクラス作成して
解説していきます。
まずCarクラスにある
各メソッドをテストする必要があり
ここではoiling()とdistance()が該当します。
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 |
public class Car { // 車種名 String carName; // 燃料 int fuel; // 給油 void oiling() { this.fuel = 80; System.out.println(this.carName + "は、ガソリンスタンドで給油した"); } // 走行距離 void distance(int km) { // 1kmで消費する燃料 int num = km / 10; // 給油した燃料から消費した燃料を算出 this.fuel -= num; System.out.println(km + "km走って" + num + "Lのガソリンを消費した"); System.out.println("残りの燃料は" + this.fuel + "Lです。"); } } |
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import org.junit.After; import org.junit.Before; import org.junit.Test; public class CarTest { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); @Before public void setUpStreams() { System.setOut(new PrintStream(outContent)); } @After public void cleanUpStreams() { System.setOut(System.out); } @Test public void oilingTest01() { Car c = new Car(); // 値をセット c.carName = "テスト車"; // oiling()メソッドを実行 c.oiling(); // 期待値を設定 final String expected = "テスト車は、ガソリンスタンドで給油した" + System.lineSeparator(); // 実際の値を取得 final String actual = outContent.toString(); // assertEqualsで判定 assertEquals(expected, actual); } @Test public void distanceTest01() { Car c = new Car(); StringBuilder sb = new StringBuilder(); // 改行 String ln = System.lineSeparator(); // 値をセット int km = 100; c.fuel = 60; // distance()メソッドを実行 c.distance(km); // 期待値を設定 sb.append("100km走って10Lのガソリンを消費した"); sb.append(ln); sb.append("残りの燃料は50Lです。"); sb.append(ln); final String expected = sb.toString(); // 実際の値を取得 final String actual = outContent.toString(); // assertThatで判定 assertThat(actual, is(expected)); } } |
テスト実行結果
assertEqualsメソッドの場合
ユーザの設定した期待値と実際の値が
イコールであればソースコードの整合性が
取れていると判断できます。
それはテストに成功したことを表しています。
違う場合はテストに失敗し
ソースコードの整合性がないことになります。
oilingTest01()に記載してあるassertEquals()の解説
1 |
assertEquals("期待値", "実際の値"); |
distanceTest01()に記載してあるassertThat()の解説
1 |
assertThat("実際の値", is("期待値")); |
またassertThat()を使用することで、
期待しない値との検証することも可能です。
1 |
assertThat("実際の値", is(not("期待しない値"))); |
JUnit4で使用される基本的なassertThatメソッド
Assertクラスのメソッドの1つになり
hamcrest.CoreMatchersクラスをインポートすると使用が可能です。
1 |
import static org.hamcrest.CoreMatchers.*; |
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 |
allOf →"指定した全ての比較メソッドがtrueであるかチェック" anyOf →"指定した比較メソッドが1つでもtrueであるかチェック" is →"期待値と実際の値が同じであるかチェック、equalToのショートカット" not →"論理値を反転する" equalTo →"期待値と実際の値が同じであるかチェック" instanceOf →"指定したクラスのインスタンスであるかチェック" sameInstance →"同じインスタンスであるかチェック" nullValue →"nullチェック" notNullValue →"not nullチェック" hasItem →"指定した値を保持しているかチェック。 org.junit.matchers.JUnitMatchers.hasItemは@Deprecatedです" hasItems →"指定した値を保持しているかチェック。 org.junit.matchers.JUnitMatchers.hasItemsは@Deprecatedです" containsString →"実際の値(文字列)が指定した文字列を含んでいるかチェック。 org.junit.matchers.JUnitMatchers.containsStringは@Deprecatedです" both →"指定した比較メソッドが全てtrueであるかチェック(and()メソッドを併用)。 org.junit.matchers.JUnitMatchers.bothは@Deprecatedです" either →"指定した比較メソッドが1つでもtrueであるかチェック(or()メソッドを併用) org.junit.matchers.JUnitMatchers.bothは@Deprecatedです" |
ユニットテストを使って発見される
バグのほとんどが境界条件に
関連しています。
逆に言えば境界条件の観点で
試験項目を作成することができれば、
良いユニットテストを行ったと言えるでしょう。
CORRECTに従って、
テスト対象のメソッドの中に
同等の条件が発生するか考慮し、
再現性のあるテストにしてください。
C onformance(適合)O rdering(順序)R ange(範囲)R eference(参照)E xisstence(存在)C ardinality(要素数)T ime(時間)
期待値の形式に適合しているか
期待値の集合は適切な順序に並び替えられているか
期待値は最小値と最大値の範囲内にあるか、閾値は妥当か
自身が直接コントロールできない外部のコードを参照していないか
期待値はnull、ゼロ、空(ブランク)でないか
期待値は十分な個数を満たしているか
適切なタイミングや一定順序で発生し、
処理結果となる期待値は想定される時間内に完了するか
この記事へのコメントはありません。