2016年06月06日(月) [長年日記]
■ [java] JUnitでparameterized testなどを使うサンプル
6月からJavaを使っている。JUnitのパラメータ化テストなどの機能を使ったので忘れないようにメモ。
- テストケースを束ねるEnclosed。
- テストケースをパラメータ化して複数のテストデータを与えたテストを行うParameterized tests。
- 例外を捕捉するExpectedException Rules。
を使った。パラメータ化テストは以前にTheoriesを使ったことがあるのだけれど、今回はParameterized testsを使ってみた。
次のサンプルでは、テストメソッドは testAdd(), testAdd2(), testDivide() の3つだけだけれどパラメータ化により15件のテストが実行される。testDivide()の実装はいまいち。
// テスト対象のクラス public class Calculator { public static int add(int x, int y) { return x + y; } public static int divide(int x, int y) { return x / y; } }
import java.util.Arrays; import org.junit.Test; import static org.junit.Assert.*; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import static org.hamcrest.CoreMatchers.is; import org.junit.Rule; import org.junit.experimental.runners.Enclosed; import org.junit.rules.ExpectedException; import org.junit.runners.Parameterized.Parameter; // Calculatorのadd()とdivide()のテストを束ねるクラス。 @RunWith(Enclosed.class) public class CalculatorTest { // Calculator::add のテスト @RunWith(Parameterized.class) public static class AddTest { // AddTest用のテストパラメータ @Parameters(name = "{index}: {0}") public static Iterable<P> data() { return Arrays.asList( new P(1, 1, 2), new P(1, 2, 3), new P(0, 1, 1), new P(-1, 1, 10), // わざとテストを失敗させる new P(-1, 1, 0) ); } // AddTest用テストパラメータを保持するクラス public static class P { int x; int y; int expected; P(int x, int y, int expected) { this.x = x; this.y = y; this.expected = expected; } @Override public String toString() { return String.format("x=%d, y=%d", x, y); } } // テストパラメータはメンバ変数に保持することになる @Parameter public P p; // これがテスト本体 @Test public void testAdd() { assertThat(Calculator.add(p.x, p.y), is(p.expected)); } @Test public void testAdd2() { assertThat(Calculator.add(p.y, p.x), is(p.expected)); } } // Calculator::divide のテスト @RunWith(Parameterized.class) public static class DivideTest { @Parameters(name = "{index}: {0}") public static Iterable<P> data() { return Arrays.asList( new P(1, 1, 1), new P(1, 2, 0), new P(0, 1, 0), new P(-1, 0, null), // 例外が投げられるケース new P(-1, 1, null) // わざとテストを失敗させる ); } public static class P { int x; int y; Integer expected; P(int x, int y, Integer expected) { this.x = x; this.y = y; this.expected = expected; } @Override public String toString() { return String.format("x=%d, y=%d", x, y); } } @Parameter public P p; // 例外を捕捉するのにExpectedExceptionルールを使う @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void testDivide() { // expectedがnullなら例外を捕捉することにする if (p.expected == null) thrown.expect(ArithmeticException.class); int result = Calculator.divide(p.x, p.y); if (p.expected != null) assertThat(result, is(p.expected)); } } }
Testsuite: CalculatorTest Tests run: 15, Failures: 3, Errors: 0, Skipped: 0, Time elapsed: 0.047 sec Testcase: testDivide[4: x=-1, y=1](CalculatorTest$DivideTest): FAILED Expected test to throw an instance of java.lang.ArithmeticException junit.framework.AssertionFailedError: Expected test to throw an instance of java.lang.ArithmeticException Testcase: testAdd[3: x=-1, y=1](CalculatorTest$AddTest): FAILED Expected: is <10> but: was <0> junit.framework.AssertionFailedError: Expected: is <10> but: was <0> at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20) at CalculatorTest$AddTest.testAdd(CalculatorTest.java:56) Testcase: testAdd2[3: x=-1, y=1](CalculatorTest$AddTest): FAILED Expected: is <10> but: was <0> junit.framework.AssertionFailedError: Expected: is <10> but: was <0> at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20) at CalculatorTest$AddTest.testAdd2(CalculatorTest.java:61)