パラメータ化テストとは
ひとつのテストケースに対し、複数パターンのパラメータをひとまとまりにして一気にテストすることをいう。
どのパラメータでテストが失敗したのかを確認することができる。
実装
日付の年月日を文字列で受け取りDate型に変換する。
その日付がカレンダー上に存在する有効な日付であれば、trueを
カレンダー上に存在しない無効な日付であれば、例外(ParseException)を
空文字の場合は、falseを返却するメソッドを実装した。
package calc;
import java.text.DateFormat;
import java.text.ParseException;
/**
* 日付チェッククラス
*/
public class DateCheck {
/**
* 入力値の日付がカレンダーに存在する日付かを判定
* yyyy-MM-ddの場合、yyyy/MM/ddに変換する
*
* @param dateStr yyyy/MM/dd
* @return boolean
* @throws ParseException
*/
public boolean checkDate(String dateStr) throws ParseException {
// 空チェック、桁数チェック
if("".equals(dateStr) || dateStr == null || dateStr.length() < 8) {
return false;
}
dateStr = dateStr.replace("-", "/");
DateFormat date = DateFormat.getDateInstance();
// 日付/時刻解析を厳密に行うかどうかを設定
date.setLenient(false);
try {
// 日付文字列をDate型に変換
date.parse(dateStr);
return true;
} catch (ParseException e) {
// 変換処理失敗時の処理
throw new ParseException("有効な日付ではありません", 0);
}
}
}
DateFormatクラスのsetLenient()をfalseにすることで、年月日の解析を厳密に行うよう設定。
デフォルトだとtrueで設定されており、以下のように機転を利かせてくれるが今回はそれを無効化する。
例:2020/01/32 → 2020/02/01
テストケースを考える
-
正常系
1年が365日あり、それらを全てテストするのは工数的に現実的ではないだろう。
よって同値分割と限界値の観点から、月の初日と最終日に絞って正常系(有効な日付)をテストする。
月によって最終日が異なるため、月ごとに最終をパラメータとして設定する。 -
異常系
月の最終日を1日超えるようパラメータを設定する。
あと、yyyy/MM/ddとyyyy-MM-dd以外のフォーマットでパラメータを設定。
空文字やnullが設定されたときのテストケースも作成する。
パラメータ化テストを書く
- 正常系
JUnit4までではパラメータをひとまとまりにするのに、@DataPointsや@DataPointでパラメータを設定し、
テストメソッドに@Theoryを設定していた。
JUnit5からはテストメソッドに、@ParameterizedTestを設定し、@ValueSourceでパラメータを設定する。
/**
* 日付チェックテストクラス
*/
class DateCheckTest {
DateCheck dateCheck;
@BeforeEach
void setUp() {
dateCheck = new DateCheck();
}
/**
* 正常系 yyyy/MM/dd yyyy-MM-dd
* @throws ParseException
*/
@ParameterizedTest
@ValueSource(strings = {"2022/01/01","2022/01/31","2022-01-01","2022-01-31"
,"2022/02/01","2022/02/28", "2022-02-01","2022-02-28"
,"2022/03/01","2022/03/31", "2022-03-01","2022-03-31"
,"2022/04/01","2022/04/30", "2022-04-01","2022-04-30"
,"2022/05/01","2022/05/31", "2022-05-01","2022-05-31"
,"2022/06/01","2022/06/30", "2022-06-01","2022-06-30"
,"2022/07/01","2022/07/31", "2022-07-01","2022-07-31"
,"2022/08/01","2022/08/31", "2022-08-01","2022-08-31"
,"2022/09/01","2022/09/30", "2022-09-01","2022-09-30"
,"2022/10/01","2022/10/31", "2022-10-01","2022-10-31"
,"2022/11/01","2022/11/30", "2022-11-01","2022-11-30"
,"2022/12/01","2022/12/31", "2022-12-01","2022-12-31"
,"9999/12/31","9999-12-31"
})
void 有効な日付チェック(String date) throws ParseException {
assertTrue(dateCheck.checkDate(date));
}
これで@ValueSourceで設定したパラメータ、50パターン全てに対しテストを行える。
テストに失敗したとき、どのパラメータで失敗したかの確認も行える。
@CsvSourceを使用する方法もある。
引数が複数あるメソッドをテストする際に使用する。
また、入力値と期待値を纏めてパラメータ化することもできる。
ただし記載が直感的に分かりづらく可読性が下がるため、使用には注意が必要。
/**
* CsvSourceを使用したテスト
* @throws ParseException
*/
@ParameterizedTest
@CsvSource({"2022/01/01, true", "2022/01/31, true", "2022-01-01, true","2022-01-31, true"
,"2022/02/01, true","2022/02/28, true", "2022-02-01, true","2022-02-28, true"
})
void 有効な日付チェック2(String date, boolean validDate) throws ParseException {
assertEquals(validDate, dateCheck.checkDate(date));
}
- 異常系
フォーマット違いの日付についてパラメータ化テストを行う。
正常系と同じ要領で@ValueSourceでパラメータ化する。
/**
* 例外 フォーマットの相違
*/
@ParameterizedTest
@ValueSource(strings = {"20220101","20220131"
,"20220201","20220228"
})
void フォーマット相違による例外(String date) throws ParseException {
ParseException ex = assertThrows(ParseException.class, () -> dateCheck.checkDate(date));
assertEquals("有効な日付ではありません", ex.getMessage());
}
例外メッセージの確認も含めてテストできる。
次にカレンダーに存在しない不正な日付をパラメータ化する。
/**
* 例外 不正な日付
*/
@ParameterizedTest
@ValueSource(strings = {"2022/01/32","2022/02/29"
,"2022/03/32","2022/04/31"
,"2022/05/32","2022/06/31"
,"2022/07/32","2022/08/32"
,"2022/09/32","2022/10/32"
,"2022/11/32","2022/12/32"
})
void 不正な日付(String date) throws ParseException {
ParseException ex = assertThrows(ParseException.class, () -> dateCheck.checkDate(date));
assertEquals("有効な日付ではありません", ex.getMessage());
}
桁数チェック、空チェック、nullチェックのテストケースも作成する。
nullは@ValueSourceでパラメータ化できない。
@Test
void 桁数の足りない日付() throws ParseException {
assertFalse(dateCheck.checkDate("01/01"));
}
@Test
void 日付が空() throws ParseException {
assertFalse(dateCheck.checkDate(""));
}
@Test
void 日付がnull() throws ParseException {
assertFalse(dateCheck.checkDate(null));
}
まとめ
パラメータ化することでひとつのテストケースで複数のパラメータについてテストできるため、コードの可読性が上がる。
パラメータを追加する場合も、@ValueSourceにパラメータを追加するだけでよいので、変更容易性も上がる。