https://www.amazon.co.jp/dp/477415377X
これのまとめ。自分の言葉で表現しないとちゃんと理解できないので。あと自分で復習したくなったとき用。
Part1 jUnit入門
- ユニットテストとは、最も小さい粒度のテストであり、実行できる仕様書となることが特徴だ。さらにその目的は、全てのテストをきちんと書いておけば、影響範囲を気にせず、デグレードを恐れずソースコードを変更できるということを達成するためである
- 検証はまとめて行わずフィールドごとに行う、もしくはカスタムMatcherを使おう。でないとどこが問題かが分かりにくい。
- テストメソッドのthrows句はthrows Exceptionでエラーを詳細に列挙しなくてよい。したところで何もテストに影響は与えない
- テスト対象のクラスやオブジェクトは
sut(System Under Test)と表記し、はっきりさせる - 期待値は
expected、実測値はactualと表記することで分かりやすくなる。プロダクトのソースと違い意味合いを変数名にするよりこちらの方がわかりやすい - できるだけテストを行いやすい(関数的な)メソッドを書こう
- メソッドが戻り値を持つ
- 副作用がない
- 同じ状態、同じパラメータの場合常に同じ値を返す
- SetUp(準備), Exercise(実行), Verify(検証)を分けてテストメソッドを書こう
-
@DataPointsでfixturesをまとめた場合、どのようなデータで失敗したかがメッセージで分からない。assertThat(msg, actual, expected)を活用しよう
Tips
例外の送出を検証する場合
@Test(expected = IllegalArgumentException.class)指定時間で終わらない場合に失敗させる
@Test(timeout = 100L)テストを実行しない
@Ignore各種メソッドに貼るアノテーション
| アノテーション | 命名 | メモ |
|---|---|---|
@Before |
public void setUp() throws Exception | 各@Testの前に1度実行される |
@After |
public void tearDown() throws Exception | 各@Testの後に1度実行される |
@BeforeClass |
public void setUpClass() throws Exception | 最初の@Testの前に1度実行される |
@AfterClass |
public void setUpClass() throws Exception | 最後の@Testの後に1度実行される |
つまり、順序で言うとテストケースが2件ある場合は@BeforeClass→@Before→@Test→@After→@Before→@Test→@After→@AfterClassとなる
// TODO サンプルつくる
Part2 jUnitの機能と拡張
- テストをまとめて行うにはSuiteを使えばいいよ。でも結局Mavenとか使う方が便利だよね
- テストコードには同じようなコードが登場しやすい。かといってそれらをまとめるとテストケースの意図が不明瞭になる
- テストクラス内では
@RunWith(Enclosed.class)を使ってテストをカテゴリごとに分けよう。カテゴリはデータの状態をを基準に分けるとよいかも。なぜならそうすると@Beforeの処理をうまくまとめられるはずなので。// TODO サンプルつくる - テストクラス間をまたぐ処理を書きたくなったら親クラスを作りがちだが、これは大きな親クラスを作りがちになる手法なので、Utilクラス等を推奨する
- 実際にテストを実行する際に必要なオブジェクトや入力値、期待値といったものをまとめて
fixtures(備品という意味)と呼ぶ。テストコードではここがどうにも長くなってしまいがちなのでここを工夫しよう - ユニットテストではfixturesはケースごとに独立しているべき、が基本戦略
- JUnitではケースごとにテストクラスのインスタンスが生成されケースが実行される。そのためクラスのインスタンス変数等はケースごとに初期化される
- fixturesのセットアップにはいくつかパターンがあるよ // TODO サンプルかく
- インラインセットアップ(テストケースの中に書く)
- 暗黙的セットアップ(
@Beforeに書く。ただ、そこに書くのは共通部分だけでケースの中にも書くのもあり) - staticメソッドに切り出す
- 外部ファイル(yaml,xml)等を用いたセットアップ
- 1つのケースに色んなパターンのパラメータでテストを試したい場合は
@Theoryと@DataPointを使おう - テストランナーを軽く拡張するのが@Rule。tempFolderを簡単に作れたりする
Tips
便利そうなMatcher
| Matcher | Sample | Note |
|---|---|---|
| nullValue | is(nullValue()) | |
| not | is(not(0)) | |
| notNullValue | is(notNullValue()) | |
| sameInstance | is(sameInstance(expected)) | プリミティブ型に対して使うとオートボクシングされた参照が比較対象となる |
| instanceOf | is(instanceOf(Sample.class)) | |
| hasItem | assertThat(sut.getList(), hasItem("Hello")) |
hasItemsもあるよ |
その他は、greater, less, empty, is, same, equalとかで Ctrl+Space すれば幸せになれるかも。
カテゴリ化したテストを実行するサンプル
// TODO ちゃんとサンプル作る
@RunWith(Categories.class)
@ExcludeCategory(SlowTests.class)
@SuiteClasses(SlowAndFastTest.class)
public class CategoriesTests {
}