LoginSignup
1
1

More than 1 year has passed since last update.

JUnit5でのパラメータ化テスト

Posted at

パラメータ化テストとは

ひとつのテストケースに対し、複数パターンのパラメータをひとまとまりにして一気にテストすることをいう。
どのパラメータでテストが失敗したのかを確認することができる。

実装

日付の年月日を文字列で受け取りDate型に変換する。
その日付がカレンダー上に存在する有効な日付であれば、trueを
カレンダー上に存在しない無効な日付であれば、例外(ParseException)を
空文字の場合は、falseを返却するメソッドを実装した。

DateCheck.java
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でパラメータを設定する。
DateCheckTest.java
/**
 * 日付チェックテストクラス
 */
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を使用する方法もある。
引数が複数あるメソッドをテストする際に使用する。
また、入力値と期待値を纏めてパラメータ化することもできる。
ただし記載が直感的に分かりづらく可読性が下がるため、使用には注意が必要。

DateCheckTest.java
	/**
	 * 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でパラメータ化する。
DateCheckTest.java
	/**
	 * 例外 フォーマットの相違
	 */
	@ParameterizedTest
	@ValueSource(strings = {"20220101","20220131"
			 ,"20220201","20220228"
			 })
	void フォーマット相違による例外(String date) throws ParseException {
		ParseException ex = assertThrows(ParseException.class, () -> dateCheck.checkDate(date));
		assertEquals("有効な日付ではありません", ex.getMessage());
	}

例外メッセージの確認も含めてテストできる。

次にカレンダーに存在しない不正な日付をパラメータ化する。

DateCheckTest.java
    /**
	 * 例外 不正な日付
	 */
	@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でパラメータ化できない。

DateCheckTest.java
    @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にパラメータを追加するだけでよいので、変更容易性も上がる。

参考

JUnit実践入門 ~体系的に学ぶユニットテストの技法

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1