JUnitでパラメータ化テストを実施する

JUnitでパラメータ化テストの実施方法メモです。

JUnitでテスト対象のメソッドに対して、複数パターンの入力値を検証する方法として
パラメータ化テストを試してみました。

テスト対象クラス作成

下記の三角形クラスを使ってテストしてみます。

Triangle.java

public class Triangle {
    private final int a;
    private final int b;
    private final int c;

    public Triangle(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    // ヘロンの公式で面積を求める。
    // 簡単のため、面積は四捨五入してintで返す。
    public int area() {
        if (a == 0 || b == 0 || c == 0) throw new ArithmeticException("zero side");
        double s = (a + b + c) / 2.0;
        double area = Math.sqrt(s * (s - a) * (s - b) * (s - c));
        return (int)Math.round(area);
    }
}
テストクラス作成

Triangle.javaに対応するテストクラスとして、
TriangleTest.javaクラスを作成します。

主なポイント

@RunWith
テストランナーを指定するアノテーションです。

Enclosed
ネストしたテストクラスでテストする場合のテストランナーです。

Theories
パラメータ化テストの際に指定するテストランナーです。

@DataPoints
1つのフィールドで複数のパラメータを定義するアノテーションです。

@Theory
パラメータ化テストのテストメソッドに付与するアノテーションです。

@Rule
独自のテストランナーを定義するアノテーションです。

ExpectedException
例外を検証するためのルールです。

TriangleFixture
可読性を高める為にフィクスチャオブジェクトを定義します。
テストするパラメータを保持するオブジェクトとします。


テストコードはこんな感じになりました。
TriangleTest.java

import org.junit.Rule;
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.rules.ExpectedException;
import org.junit.runner.RunWith;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

@RunWith(Enclosed.class)
public class TriangleTest {
    @RunWith(Theories.class)
    public static class 辺の長さ0なし {
        @DataPoints
        public static TriangleFixture[] TRI = {
                new TriangleFixture(3, 4, 5, 6),
                new TriangleFixture(4, 10, 12, 19),
                new TriangleFixture(3, 3, 3, 4)
        };

        @Theory
        public void area(TriangleFixture f) throws Exception {
            Triangle t = new Triangle(f.a, f.b, f.c);
            assertThat(t.area(), is(f.expected));
        }
    }

    @RunWith(Theories.class)
    public static class 辺の長さ0あり {
        @DataPoints
        public static TriangleFixture[] TRI = {
                new TriangleFixture(0, 4, 5, 6),
                new TriangleFixture(4, 0, 12, 19),
                new TriangleFixture(3, 3, 0, 4)
        };

        @Rule
        public ExpectedException thrown = ExpectedException.none();

        @Theory
        public void area(TriangleFixture f) throws Exception {
            thrown.expect(ArithmeticException.class);
            Triangle t = new Triangle(f.a, f.b, f.c);
            t.area();
        }
    }

    static class TriangleFixture {
        int a;
        int b;
        int c;
        int expected;

        TriangleFixture(int a, int b, int c, int expected) {
            this.a = a;
            this.b = b;
            this.c = c;
            this.expected = expected;
        }
    }
}
テスト実行

IntellJ IDEAでJUnitのテストを実行してみます。
f:id:pppurple:20160615044944p:plain

うまく通りました。終わり。


【参考】