現在はテスト自動化シリーズと題しましてJUnit関連の紹介を連載中です。
さて、JUnitの開発では、「渡す引数が違うだけで同じメソッドを何度もテストする」というパラメータテストを実施することがあります。
例えば、「文字列の半角英数字チェック」のメソッドをテストしようとすれば、引数として渡すテスト対象文字列は以下のように色々なパターンが存在します。
- 半角英字
- 半角数字
- 記号
- 全角英字
- 全角数字
- ひらがな
- 空白スペース
- 以下続く……
これらのパターンに対してそれぞれテストを実行し、全て正常に期待した結果になるかどうかをチェックするJUnitソースを作成するというシチュエーションです。
では、まずはダメなパターンから行ってみましょう。
@Test
public void 半角英数字チェックのテスト() {
assertThat(TheoriesSample.isHankaku("a"),is(true));
assertThat(TheoriesSample.isHankaku("1"),is(true));
assertThat(TheoriesSample.isHankaku(","),is(false));
assertThat(TheoriesSample.isHankaku("A"),is(false));
assertThat(TheoriesSample.isHankaku("あ"),is(false));
assertThat(TheoriesSample.isHankaku("*"),is(false));
assertThat(TheoriesSample.isHankaku(""),is(true));
assertThat(TheoriesSample.isHankaku(null),is(true));
assertThat(TheoriesSample.isHankaku(" "),is(true));
}
こういう書き方はJUnitの作法としてNGです。
この場合、一つのテストメソッドで複数パターンのテストを実施していることになってしまいます。
「一つのメソッドで一つのテストパターン」
これがJUnitの作法です。
みんなが正しく作法を守ることで可読性の高い良いソースが生まれるのです。
面倒でもテストパターン毎に別々のメソッドにして下さい。
その作法を守ったパターンが以下になります。
@RunWith(Enclosed.class)
public class TheoriesSampleTest {
public static class 半角英数字チェックのテスト {
@Test
public void 半角英数字チェック_半角英字はtrue() {
assertThat(TheoriesSample.isHankaku("a"),is(true));
}
@Test
public void 半角英数字チェック_半角数字はtrue() {
assertThat(TheoriesSample.isHankaku("1"),is(true));
}
@Test
public void 半角英数字チェック_記号はfalse() {
assertThat(TheoriesSample.isHankaku(","),is(true));
}
//以下続く
}
}
これなら「一つのメソッドで一つのテストパターン」のルールを守れます。前回の記事で紹介した「Enclosedアサーション」を使えば「半角英数字チェックのテスト」でグループ化出来るので、メソッドが増えてもソースの見通しは比較的良い状態を保てます。
とはいえ、いくら正しい書き方と言っても、これは面倒でしょう。
「引数が1コ違うだけで他は全部同じなんだから、引数以外は共通化したい」と思うのがプログラマー精神です。
そこでご紹介するのが、今回記事のテーマ「Theoriesアサーション」です。
この機能は、上記のように「テストを実行するメソッド部分は同じだが、渡すパラメータだけは変えたい」という要望に対応するものです。
まずは以下にサンプルを記載します。
@RunWith(Enclosed.class)
public class TheoriesSampleTest {
@RunWith(Theories.class)
public static class 半角英数字チェックのテスト_true系 {
@DataPoint
public static String 半角英字 = "a";
@DataPoint
public static String 半角数字 = "1";
@DataPoint
public static String 空白 = "";
//省略
@Theory
public void 半角英数字チェックパラメータテスト(String str) {
assertThat(TheoriesSample.isHankaku(str),is(true));
}
}
@RunWith(Theories.class)
public static class 半角英数字チェックのテスト_false系 {
@DataPoint
public static String 記号 = ",";
@DataPoint
public static String 全角英字 = "A";
@DataPoint
public static String ひらがな = "あ";
//省略
@Theory
public void 半角英数字チェックパラメータテスト(String str) {
assertThat(TheoriesSample.isHankaku(str),is(false));
}
}
}
ここで新登場のアサーションは三つです。
- @RunWith(Theories.class):このテストクラスがTheoryによる繰り返しであることを示す
- @DataPoint:繰り返し時に渡すパラメータ
- @Theory:テストメソッド本体
今まで引数として渡していたパラメータは「@DataPointアサーション」をつけたフィールド変数として定義します。
そして、そのクラスに「@RunWith(Theories.class)」を、テストメソッドに「@Theory」を付与することで、定義した全ての@DataPointがテストメソッドに繰り返し渡されるという構造です。
つまり、「@DataPoint」の定義だけをペタペタと増やしていけば、大量にあるテストパターンのパラメータも全て網羅出来るわけです。
この結果がエラーになった場合は、以下のように表示されます。
なるほど。
普通のテストケースだと「assertThat」の箇所が表示されますが、こちらの場合はエラーになったパラメータが表示されるわけです。
つまり、テストメソッドの中にassertThatが複数あった場合、その中のどのassertThatがエラーになったかは一目では分からないということになります。
このため、テストメソッド本体の中に記述するassertThatは一行一発で済ませるのが良いわけです。
このような場合には、過去に紹介した「カスタムMatcher」を作ることで解決して下さい。今まで紹介したJUnitの機能を組み合わせることで、スタイリッシュなJUnitソースを開発出来るのです。
次回予告
今回の記事ではTheoriesアサーションの簡単な例を紹介しました。しかし、
- 「@DataPointでテストメソッドに渡している引数がString型1コしか無いけど、同時に複数個渡したい場合はどうすればいいの?」
- 「期待する結果がtrue,falseの2パターンだけならこれでいいけど、引数毎に違う場合はどうするんだ?」
という疑問が沸いた方もいらっしゃるかと思います。
そう、上記の例では、テストメソッドに渡す引数は1コ限定、「assertThat」の期待値部分もtrue/falseの固定値と、柔軟性が無いのです。
プロジェクトの都合に合わせて柔軟に対応するにはもう一息、JUnitの機能と言うより、書き方のテクニックが必要になります。
次回はその書き方のテクニック「Fixture」についてご説明します。
0 件のコメント:
コメントを投稿