概要
JUnit4のDataPointsによるテストとFixtureと流れるようなインターフェース
内容
JUnit4のDataPointsによって、テストをパラメータ化することができます。
その際、テストケースの入れ物としてFixtureを利用します。
Fixtureは下記ページのような内容に対してフィールドに変数を設定し、
その内容をコンストラクタ経由で配列に設定します。
JUnit4のDataPointsによるテストとパラメータ化の基準
この際、項目が増えるとコンストラクタの項目数が増加して一見して
どのようなテストデータが設定されているか分かりにくくなります。
そこで、流れるようなインターフェースを利用して設定内容を分かりやすくします。
サンプルコード
テストコード仕様やテストコード以外のソースコードは下記リンクのサンプルと同じものとする。
JUnit4のDataPointsによるテストとパラメータ化の基準
package parameterized; import static jp.co.dgic.testing.framework.DJUnitTestCase.setReturnValueAtAllTimes; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import gr.java_conf.tb.tbpg_util.common.CommonUtil; import org.junit.experimental.runners.Enclosed; import org.junit.experimental.theories.DataPoints; import org.junit.experimental.theories.Theories; import org.junit.experimental.theories.Theory; import org.junit.runner.RunWith; @RunWith(Enclosed.class) public class SampleParameterized2Test { @RunWith(Theories.class) public static class GetUpperUserName { @DataPoints public static Fixture[] getFixture() { /* * ケース番号、ユーザー名、囲い文字有無、例外有無、例外メッセージ、ユーザー名期待値 */ Fixture[] fixture = { // 大文字変換なし、囲い文字有りのケース new Fixture().caseNo(1).uerName("andy").hasEnclose(true).hasException(false).errorMessage(null) .expectedUserName("【andy】"), // 大文字変換なし、囲い文字なしのケース new Fixture().caseNo(2).uerName("andy").hasEnclose(false).hasException(false).errorMessage(null) .expectedUserName("andy"), // 大文字変換あり、囲い文字有りのケース new Fixture().caseNo(3).uerName("boby").hasEnclose(true).hasException(false).errorMessage(null) .expectedUserName("【BOBY】"), // 大文字変換あり、囲い文字なしのケース new Fixture().caseNo(4).uerName("boby").hasEnclose(false).hasException(false).errorMessage(null) .expectedUserName("BOBY"), // 例外になるケース new Fixture().caseNo(5).uerName("boby12").hasEnclose(false).hasException(true).errorMessage("取り敢えず例外") .expectedUserName("boby12"), // わざとエラーになるケース new Fixture().caseNo(6).uerName("boby").hasEnclose(false).hasException(false).errorMessage(null) .expectedUserName("boby"), }; return fixture; }; @Theory public void testGetUpperUserName(Fixture fixture) { // ****テスト前処理***** // DBから取得するユーザー名をモック化 setReturnValueAtAllTimes(DbAccess.class, "getUserName", fixture.userName); SampleParameterized parameterized = new SampleParameterized(); String actualUserName; // ****テスト実行**** try { actualUserName = parameterized.getUpperUserName(fixture.hasEnclose); if (fixture.hasException) { // 例外のケースにも関わらず正常終了していたら強制的にテスト失敗 assertThat(fixture.toString(), true, is(false)); } // ****テスト結果の検証**** assertThat(fixture.toString(), actualUserName, is(fixture.expectedUserName)); } catch (Exception e) { if (!fixture.hasException) { // 正常系のケースにも関わらず例外が発生していたら強制的にテスト失敗 e.printStackTrace(); assertThat(fixture.toString(), true, is(false)); } // 例外のメッセージ検証 assertThat(fixture.toString(), e.getMessage(), is(fixture.errorMessage)); } } static class Fixture { // Fixtureのケース番号 int caseNo; // モックに設定するユーザー名。また分岐に影響する String userName; // 分岐に影響する入力値。 boolean hasEnclose; // 例外の有無 boolean hasException; // 例外のメッセージ内容 String errorMessage; // ユーザー名の期待値。分岐に影響する String expectedUserName; public String toString() { // Fixtureの内容を一括出力 return CommonUtil.getAllFiledInfo(Fixture.class, this); } public Fixture caseNo(int caseNo) { this.caseNo = caseNo; return this; } public Fixture uerName(String userName) { this.userName = userName; return this; } public Fixture hasEnclose(boolean hasEnclose) { this.hasEnclose = hasEnclose; return this; } public Fixture hasException(boolean hasException) { this.hasException = hasException; return this; } public Fixture errorMessage(String errorMessage) { this.errorMessage = errorMessage; return this; } public Fixture expectedUserName(String expectedUserName) { this.expectedUserName = expectedUserName; return this; } } } }
Fixture部を抜粋して比較
通常のFixture
/* * ケース番号、ユーザー名、囲い文字有無、例外有無、例外メッセージ、ユーザー名期待値 */ Fixture[] fixture = { // 大文字変換なし、囲い文字有りのケース new Fixture(1, "andy", true, false, null, "【andy】"), // 大文字変換なし、囲い文字なしのケース new Fixture(2, "andy", false, false, null, "andy"), // 大文字変換あり、囲い文字有りのケース new Fixture(3, "boby", true, false, null, "【BOBY】"), // 大文字変換あり、囲い文字なしのケース new Fixture(4, "boby", false, false, null, "BOBY"), // 例外になるケース new Fixture(5, "boby12", false, true, "取り敢えず例外", "boby12"), // わざとエラーになるケース new Fixture(6, "boby", false, false, null, "boby"), };
流れるようなインターフェースのFixture
/* * ケース番号、ユーザー名、囲い文字有無、例外有無、例外メッセージ、ユーザー名期待値 */ Fixture[] fixture = { // 大文字変換なし、囲い文字有りのケース new Fixture().caseNo(1).uerName("andy").hasEnclose(true).hasException(false).errorMessage(null) .expectedUserName("【andy】"), // 大文字変換なし、囲い文字なしのケース new Fixture().caseNo(2).uerName("andy").hasEnclose(false).hasException(false).errorMessage(null) .expectedUserName("andy"), // 大文字変換あり、囲い文字有りのケース new Fixture().caseNo(3).uerName("boby").hasEnclose(true).hasException(false).errorMessage(null) .expectedUserName("【BOBY】"), // 大文字変換あり、囲い文字なしのケース new Fixture().caseNo(4).uerName("boby").hasEnclose(false).hasException(false).errorMessage(null) .expectedUserName("BOBY"), // 例外になるケース new Fixture().caseNo(5).uerName("boby12").hasEnclose(false).hasException(true).errorMessage("取り敢えず例外") .expectedUserName("boby12"), // わざとエラーになるケース new Fixture().caseNo(6).uerName("boby").hasEnclose(false).hasException(false).errorMessage(null) .expectedUserName("boby"), };
前者は項目順がどの項目をセットしているか暗記するか、
都度Fixtureのコンストラクタを確認する必要がありましたが、
後者は設定内容が一目瞭然です。