概要
- JUnit 5 + Apache Maven による Java の自動テストについて基本的なサンプルを書く
今回の環境
- Java 11 (AdoptOpenJDK 11.0.8+10)
- JUnit Jupiter 5.7.0
- Apache Maven 3.6.3
- Maven Surefire Plugin 3.0.0-M5
JUnit 5 + Apache Maven の基本的なサンプル
ソースコード一覧
├── pom.xml
└── src
├── main
│ └── java
│ └── myapp
│ └── Calc.java
└── test
└── java
└── myapp
└── CalcTest.java
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mygroup</groupId>
<artifactId>myapp</artifactId>
<packaging>jar</packaging>
<version>1.0.0</version>
<name>myapp</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
<plugins>
<!-- JUnit 5 でのテスト実行に必要なプラグインを導入 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
</plugin>
</plugins>
</build>
<dependencies>
<!-- テストコードの記述に必要なライブラリを導入 -->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
参考:
- JUnit 5 User Guide - 4.2.2. Maven
- Maven Surefire Plugin – Introduction
- Maven Repository: org.junit.jupiter » junit-jupiter-api
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 の検証");
}
}
参考:
テスト成功時の例
$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------------< mygroup:myapp >----------------------------
[INFO] Building myapp 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
(中略)
[INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) @ myapp ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running myapp.CalcTest
CalcTest 開始
CalcTest のテストメソッドをひとつ開始
testMinus を実行: 5 - 2 = 3
CalcTest のテストメソッドをひとつ終了
CalcTest のテストメソッドをひとつ開始
testPlus を実行: 2 + 3 = 5
CalcTest のテストメソッドをひとつ終了
CalcTest 終了
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.087 s - in myapp.CalcTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
テスト失敗時の例
$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------------< mygroup:myapp >----------------------------
[INFO] Building myapp 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
(中略)
[INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) @ myapp ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running myapp.CalcTest
CalcTest 開始
CalcTest のテストメソッドをひとつ開始
testMinus を実行: 5 - 2 = 3
CalcTest のテストメソッドをひとつ終了
CalcTest のテストメソッドをひとつ開始
testPlus を実行: 2 + 3 = 5
CalcTest のテストメソッドをひとつ終了
CalcTest 終了
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.063 s <<< FAILURE! - in myapp.CalcTest
[ERROR] myapp.CalcTest.testMinus Time elapsed: 0.026 s <<< FAILURE!
org.opentest4j.AssertionFailedError: 5 - 2 = 3 の検証 ==> expected: <3> but was: <7>
at myapp.CalcTest.testMinus(CalcTest.java:53)
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] CalcTest.testMinus:53 5 - 2 = 3 の検証 ==> expected: <3> but was: <7>
[INFO]
[ERROR] Tests run: 2, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
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))
);
}
}
参考:
テスト失敗時の例
$ mvn test
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------------< mygroup:myapp >----------------------------
[INFO] Building myapp 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
(中略)
[INFO] --- maven-surefire-plugin:3.0.0-M5:test (default-test) @ myapp ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running myapp.CalcTest
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.067 s <<< FAILURE! - in myapp.CalcTest
[ERROR] myapp.CalcTest.testPlus Time elapsed: 0.044 s <<< FAILURE!
org.opentest4j.MultipleFailuresError:
Multiple Failures (2 failures)
org.opentest4j.AssertionFailedError: expected: <99> but was: <100>
org.opentest4j.AssertionFailedError: expected: <11> but was: <60>
at myapp.CalcTest.testPlus(CalcTest.java:15)
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] CalcTest.testPlus:15 Multiple Failures (2 failures)
org.opentest4j.AssertionFailedError: expected: <99> but was: <100>
org.opentest4j.AssertionFailedError: expected: <11> but was: <60>
[INFO]
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
例外発生テストのサンプル
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);
}
}