つかびーの技術日記

情報系修士卒のWeb系技術日記です。現在のフォーカス分野はアドテクです。

assertEqualsするだけがJUnitじゃなかった!機能の紹介

   

ユニットテストって良いですよね!デグレード(リグレッション)に気付けたり、テストコードから仕様が読み取れたり、設計も改善されますし、リファクタリングに使えるし・・・色々良い感じです。

今日はユニットテストのツール、JUnitの話題です。

Javaプログラマには必須のライブラリ・フレームワークの1つであるJUnitですが、恥ずかしいことに、私の習熟度は低いです。理由は、過去にある程度使えるようになった時点で学習を辞めてしまったことと、仕事では色々な問題のせいで使う機会が少ないこと、の2点です。

今回、以下のなかなか良さげな本の存在を知ったのでちゃんと学習してみることにしました。

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

著者/訳者:渡辺 修司

出版社:技術評論社( 2012-11-21 )

定価:

Amazon価格:¥ 3,564

単行本(ソフトカバー) ( 480 ページ )

ISBN-10 : 477415377X

ISBN-13 : 9784774153773


使えそうな良いと思った機能・テクニック

assertThat

自分が初めてJUnitに触れたときはこんな機能ありませんでした。そのため、JUnitと言えばassertEqualsという認識だったんですが、こっちのassertThatメソッドの方が断然良いですね!これからはこちらを使います!

assertThatはMatcherというオブジェクトを利用してマッチングを行う点がassertEqualsと大きく異なります。どのように違うかは以下の通りです。

例えばこのようなテストケースがあるとします。

(actualの値はテスト対象のメソッドから受け取ったことにしてください。ここでは例のため直接Dateをnewしていますが。)

このテストを実行すると当然レッドバー、テスト失敗です。なぜなら1秒ずれていますので。

Dateのような日付型を扱うとき、日未満の単位、つまり時、分、秒は何でも良い、拘らない、というシーンが多々あります。上記のテストで2014/1/1かどうかを検証するというコードを書く場合どうしたらいいのでしょうか。

以下は解の1つですが、微妙です。

このようなケースはassertThatを利用するとスマートに解決できます。assertThatはMatcherというオブジェクトを利用してマッチングを行います。そのため、このMatcherを利用シーンに合わせて選択すれば良いわけです。

Matcherはそれほど苦労することなく独自に作成することができますが、ここでは独自に作成することはしません。Dateは標準APIですし、きっと世の中のどこか、特にGitHubなんかにDateを検証するMatcherを公開している人がいるはずです。

これは実際居て、以下にて公開されています。

https://github.com/modularit/hamcrest-date

いやっほう!stewbisありがとう!Maven Centralにも登録されている!さらにBSDライセンスで僕たちは(比較的)自由だ!

早速上記のサイト通りpom.xmlに依存ライブラリを追加し、hamcrest-dateを利用します。

これはグリーンバーで成功します。sameDayは年、月、日までを検証するためです。2014/1/1と2013/1/1とかは勿論年度が異なるのでレッドになりますが、上記のような秒が異なるケースはグリーンになります。

assertThatとMatcher非常に便利です。

テストメソッド名は日本語で

これは前々から思ってたことなのですが、上記の本を読んで考えが固まりました。テストメソッドは日本語で書いていいんだ・・・!

業務では会社やプロジェクトの特性上、テストケースを書くことは少ないんですが、それでも少しはあります。そんなとき、テスト名は以下のように付けていました。

理由はテストケースを記述したExcel表が別にあるので、それと対応付けるために番号が必要だったり、少しは分かりやすくしようとSuccessとかは付けるようにしたりと、そんな感じです。

前提条件やテストの概要はJavadocコメントに頑張って書いていましたが・・・ずっと微妙な気持ちでもやもやしていました。(既に他の人が作ったサンプル実装を真似る必要があって簡単には改善できない状態でした)

テストメソッド名は日本語で書いていいんですね!

頭の”test”は慣習なのでそのまま残して後ろに日本語名を付けて分かりやすくします。日本語部分は5W1Hとかを考えて、プロジェクトである程度方針を決めた方が良い気がします。

Enclosedテストランナー

テストクラスの中にインナークラスを作成する、というものです。

前提条件ごとに構造化できたりするので良い感じですね。

上記ではnamesをテスト対象のメソッドに与えることを想定しているので、各テストメソッド内でnamesを構築した方が良いかもしれませんが、DBの初期化を行う場合などは確実に「前提条件」と言えるので役立ちそうです。

パラメータ化テスト

テストケースを書くとき、テスト対象のメソッドに与えるパラメータとその予測値が異なるだけなのに、同じようなテストケースメソッドを何度も書かないといけないことがよくあります。そんなときはパラメータ化テスト(Theoriesテストランナー)を利用します。

例えば以下のようなで。

これを実行するとテストが3回走ります。もし3つあるFixtureのうち、3つ目でエラーが発生した場合、

エラー発生: test_パラメータ化テスト(fixtures[2])というような表示が出るので、どこでエラーが出たか分かります。

他にも色々

上記の本では他にも様々なテクニックが公開されていました。

  • Matcher APIのnotでassertThat(actual, is(not(expected)));と書ける
    英文なので自然な形になる
  • Categoriesテストランナーでテストをカテゴリー化して一部だけ実行
    DBのテストだけは分けておいて、スローテスト問題解決
  • ルール
  • テストダブル(モックのライブラリを使ってテスタビリティ向上)

などなど。

非常に勉強になりました。JUnitの知識がバージョン3で止まっている人や、自分と同じくassertEqualsばっかり使っている人にはお勧めの1冊です。

JUnit4をマスターして頑張ってユニットテストが十分されている開発を目指します。

 - ツール