概要
- JUnit 5 + Gradle による Java の自動テストについて基本的なサンプルを書く
Junit 5 とは
- JUnit は Java の自動テスト用フレームワーク
- JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
- JUnit Platform: テスト実行プラットフォーム
- JUnit Jupiter: テストコード実装用APIとテストエンジンを提供
- JUnit Vintage: JUnit 3 と JUnit 4用のテストコード実装用APIとテストエンジンを提供
今回の環境
- Java 11 (OpenJDK 11.0.2)
- JUnit Platform 1.5.2
- JUnit Jupiter 5.5.2
- Gradle 6.0.1
JUnit 5 + Gradle の基本的なサンプル
ソースコード一覧
├── build.gradle
├── settings.gradle
└── src
├── main
│ └── java
│ └── myapp
│ └── Calc.java
└── test
└── java
└── myapp
└── CalcTest.java
build.gradle
build.gradle
plugins {
id 'java'
}
repositories {
jcenter()
}
dependencies {
// Junit Jupiter 5.5.2 を導入
// 依存関係で以下等が導入される
// junit-jupiter-api:5.5.2
// junit-jupiter-engine:5.5.2
// junit-jupiter-platform-engine:1.5.2
testImplementation 'org.junit.jupiter:junit-jupiter:5.5.2'
}
test {
// JUnit platform を使う設定
useJUnitPlatform()
testLogging {
// テスト時の標準出力と標準エラー出力を表示する
showStandardStreams true
// イベントを出力する (TestLogEvent)
events 'started', 'skipped', 'passed', 'failed'
// 例外発生時の出力設定 (TestExceptionFormat)
exceptionFormat 'full'
}
}
参考:
- JUnit 5 User Guide
- Maven Repository: org.junit.jupiter » junit-jupiter
- TestLogging - Gradle DSL Version 6.0.1
- TestLogEvent (Gradle API 6.0.1)
- TestExceptionFormat (Gradle API 6.0.1)
settings.gradle
settings.gradle
rootProject.name = 'myapp'
Calc.java
package myapp;
public class Calc {
private int base;
// 基準となる値を設定
public Calc(int base) {
this.base = base;
}
// 足す
public int plus(int num) {
return base + num;
}
// 引く
public int minus(int num) {
return base - num;
}
}
CalcTest.java
package myapp;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CalcTest {
// テスト開始前に1回だけ実行される
@BeforeAll
static void beforeAll() {
System.out.println("CalcTest 開始");
}
// テスト開始後に1回だけ実行される
@AfterAll
static void afterAll() {
System.out.println("CalcTest 終了");
}
// 各テストメソッド開始前に実行される
@BeforeEach
void beforeEach() {
System.out.println("CalcTest のテストメソッドをひとつ開始");
}
// 各テストメソッド開始後に実行される
@AfterEach
void afterEach() {
System.out.println("CalcTest のテストメソッドをひとつ終了");
}
// テストメソッドは private や static メソッドにしてはいけない
// 値を返してもいけないので戻り値は void にする
@Test
void testPlus() {
System.out.println("testPlus を実行: 2 + 3 = 5");
Calc calc = new Calc(2);
// 第1引数: expected 想定される結果
// 第2引数: actual 実行結果
// 第3引数: message 失敗時に出力するメッセージ
assertEquals(5, calc.plus(3), "2 + 3 = 5 の検証");
}
@Test
void testMinus() {
System.out.println("testMinus を実行: 5 - 2 = 3");
Calc calc = new Calc(5);
assertEquals(3, calc.minus(2), "5 - 2 = 3 の検証");
}
}
参考:
テスト成功時の例
$ gradle test
> Task :test
myapp.CalcTest STANDARD_OUT
CalcTest 開始
myapp.CalcTest > testMinus() STARTED
myapp.CalcTest > testMinus() STANDARD_OUT
CalcTest のテストメソッドをひとつ開始
testMinus を実行: 5 - 2 = 3
CalcTest のテストメソッドをひとつ終了
myapp.CalcTest > testMinus() PASSED
myapp.CalcTest > testPlus() STARTED
myapp.CalcTest > testPlus() STANDARD_OUT
CalcTest のテストメソッドをひとつ開始
testPlus を実行: 2 + 3 = 5
CalcTest のテストメソッドをひとつ終了
myapp.CalcTest > testPlus() PASSED
myapp.CalcTest STANDARD_OUT
CalcTest 終了
BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed
テスト失敗時の例
$ gradle test
> Task :test FAILED
myapp.CalcTest STANDARD_OUT
CalcTest 開始
myapp.CalcTest > testMinus() STARTED
myapp.CalcTest > testMinus() STANDARD_OUT
CalcTest のテストメソッドをひとつ開始
testMinus を実行: 5 - 2 = 3
CalcTest のテストメソッドをひとつ終了
myapp.CalcTest > testMinus() FAILED
org.opentest4j.AssertionFailedError: 5 - 2 = 3 の検証 ==> expected: <3> but was: <7>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:150)
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:542)
at myapp.CalcTest.testMinus(CalcTest.java:48)
assertAll でまとめてテストするサンプル
サンプルコード
package myapp;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CalcTest {
@Test
void testPlus() {
Calc calc = new Calc(10);
// まとめて検証
// 途中で失敗しても停止せずにすべて検証する
assertAll(
() -> assertEquals(30, calc.plus(20)),
() -> assertEquals(99, calc.plus(90)),
() -> assertEquals(11, calc.plus(50)),
() -> assertEquals(40, calc.plus(30))
);
}
}
参考:
テスト失敗時の例
$ gradle test
> Task :test FAILED
myapp.CalcTest > testPlus() STARTED
myapp.CalcTest > testPlus() FAILED
org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
org.opentest4j.AssertionFailedError: expected: <99> but was: <100>
org.opentest4j.AssertionFailedError: expected: <11> but was: <60>
at org.junit.jupiter.api.AssertAll.assertAll(AssertAll.java:80)
at org.junit.jupiter.api.AssertAll.assertAll(AssertAll.java:44)
at org.junit.jupiter.api.AssertAll.assertAll(AssertAll.java:38)
at org.junit.jupiter.api.Assertions.assertAll(Assertions.java:2839)
at myapp.CalcTest.testPlus(CalcTest.java:15)
1 test completed, 1 failed
FAILURE: Build failed with an exception.
例外発生テストのサンプル
package myapp;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
class CalcTest {
@Test
void testPlus() {
Calc calc = new Calc(100);
// 0 で割ったら ArithmeticException が発生することを想定
ArithmeticException e =
assertThrows(ArithmeticException.class,
() -> calc.divide(0));
assertTrue(e instanceof ArithmeticException);
}
}