パラメータ化テストでの例外確認方法がわからない #junit #q

新年早々JUnitでテストを作成していたのですが、例外のテストがうまくできないことに気づいた。
(コードはjavaっぽく書いてますがgroovyで動作確認しています。)

class ASample {

    public int method(int i) {
        if (i > 10 || i < 5) {
            throw new IllegalArgumentException("不正な値です。")
        }
        // 何らかの処理
        return i
    }
}

こんなメソッドがあった場合。
例外が投げられる事をテストする場合にこんな感じに書くと思っている。

class ASampleTest1 {

    @Test(expected=IllegalArgumentException.class)
    public void 引数が11の場合は例外を投げる() {
        new ASample().method(11)
        fail("例外が投げられない")
    }

    @Test(expected=IllegalArgumentException.class)
    public void 引数が4の場合は例外を投げる() {
        new ASample().method(4)
        fail("例外が投げられない")
    }
}

今回は2つの値だからいいけれども、これが複数あった場合に面倒くさいのでパラメータだけ変えればええやん?
って事で最近学んだ「Theories」と「DataPoints」を使用してみた。
が、例外を投げるというテストの方法がわからなかったので古典的にtrycatchする事に。

@RunWith(Theories.class)
class ASampleTest2 {

    @DataPoints
    public static int[] PARAMs = [4,11]

    // こんな感じに書きたい
    //    @Theory(expected=IllegalArgumentException.class)
    //    public void 範囲外の場合には例外を投げる(int p) {
    //        new ASample().method(p)
    //        fail("例外が投げられない")
    //    }

    @Theory
    public void 範囲外の場合には例外を投げる(int p) {
        try {
            new ASample().method(p)
            fail("例外が投げられない")
        }catch (IllegalArgumentException e) {
            assertThat(e.message, is("不正な値です。"))
        }
    }
}

複数のパラメータで同一の例外が投げられる事というテストケースの作成は普通だと思うので調べたけどわからず。
別の方法を模索してたら「Rule」の「ExpectedException」を使用することで実現可能っぽかったので作成。
(ついでに例外のメッセージも確認)

@RunWith(Theories.class)
class ASampleTest3 {

    @Rule
    public ExpectedException expectedException = ExpectedException.none()

    @DataPoints
    public static int[] PARAMs = [4,11,5]

    @Theory
    public void 範囲外の場合には例外を投げる(int p) {
        expectedException.expect(IllegalArgumentException.class)
        expectedException.expectMessage("不正な値です。")
        new ASample().method(p)
    }
}

これはいい感じに動いているけど、テストがコケた場合の例外が↓の用に出力され、どのパラメータでコケたのか一発でわからない。

// この場合だと「引数が5の時にテストが失敗しました。」というようにメッセージを出力したい。
org.junit.experimental.theories.internal.ParameterizedAssertionError: 範囲外の場合には例外を投げる(PARAMs[2])
   <略>
Caused by: java.lang.AssertionError: Expected test to throw (exception with message a string containing "不正な値です。" and an instance of java.lang.IllegalArgumentException)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:118)
at org.junit.experimental.theories.Theories$TheoryAnchor$1$1.evaluate(Theories.java:133)
... 20 more

そもそもこのような場合は、一番最初のように別々にテストケースを作成するのが正しいんですかね?
けど、結果も含めてパラメータ以外は同じな訳で。
テストって難しい!