この記事はMDC Advent Calendar 2020 19日目の記事です。
はじめに
皆さん、単体テスト書いてますか?
(私自身も最近あまり書いてないですが...)
- 実装はできるのにテストコードがあまり書けない
- JUnit4までは書いたことあるけど、JUnit5はあんまり...
意外と多いそんな人たち向けに、JUnit5でテストコードを書き始めるためのお助けになればと思います。
概要
JUnit5とは
-
言わずと知れたJava開発における最もメジャーなテストフレームワークです
-
これまでのバージョンのJUnitとは異なり、JUnit5は3つのサブプロジェクトに含まれる複数のモジュールで構成されます
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage- JUnit Platform
- JVM上でテストフレームワークを起動するための基盤となる
- 上記のプラットフォーム上で動作するテストフレームワークを開発するための
TestEngine
APIを定義している - コマンドラインからプラットフォームを起動するための
Console Launcher
や、 GradleやMaven用のビルドプラグイン、JUnit4ベースのテストランナーなどを提供し、あらゆるTestEngine
を実行できるようになっている
- JUnit Jupiter
- JUnit5でテストを書くために最低限必要な依存関係をまとめたもの
- JUnit Vintage
- JUnit3またはJUnit4ベースのテストを実行するための
TestEngine
を提供する
- JUnit3またはJUnit4ベースのテストを実行するための
- JUnit Platform
-
長くなりましたが、とりあえずJUnit5でテストを書き始めたいなら、JUnit Jupiterを依存関係に追加しとけばOKです(以下はgradleのサンプル)
build.gradle
plugins {
id "java"
}
sourceCompatibility = 8
targetCompatibility = 8
[compileJava, compileTestJava]*.options*.encoding = "UTF-8"
repositories {
mavenCentral()
}
dependencies {
testImplementation "org.junit.jupiter:junit-jupiter:5.7.0"
}
サポートされるJavaバージョン
- JUnit5を実行するためには、Java8以上が必要です
テストの書き方
テストメソッド
package sample.junit5;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class JUnit5Test {
@Test
void success() {
assertEquals(12, 12);
}
@Test
void failure() {
assertEquals(5, 12);
}
}
アノテーション | 説明 |
---|---|
@Test |
付与されたメソッドがテストメソッドになる |
- アサーションメソッド(例は
assertEquals(expected, actual)
)を使い、期待値と実測値を比較する- 実際には、テスト対象メソッドを呼び出して、その戻り値と期待値を比較します
- JUnit5では、テストクラス・テストメソッドともに
public
である必要がなくなりました
前処理・後処理
package sample.junit5;
import org.junit.jupiter.api.*;
class JUnit5Test {
@BeforeAll
static void beforeAll() {
System.out.println("☆ beforeAll()");
}
@BeforeEach
void beforeEach() {
System.out.println("☆☆ beforeEach()");
}
@AfterEach
void afterEach() {
System.out.println("★★ afterEach()");
}
@AfterAll
static void afterAll() {
System.out.println("★ afterAll()");
}
@Test
void test1() {
System.out.println("~~~ test1() ~~~");
}
@Test
void test2() {
System.out.println("~~~ test2() ~~~");
}
}
実行結果
☆ beforeAll()
☆☆ beforeEach()
~~~ test1() ~~~
★★ afterEach()
☆☆ beforeEach()
~~~ test2() ~~~
★★ afterEach()
★ afterAll()
アノテーション | 説明 |
---|---|
@BeforeAll |
付与されたメソッドは、1番最初に1度だけ実行される メソッドはstaticである必要がある |
@BeforeEach |
付与されたメソッドは、各テストメソッドの前に毎回実行される |
@AfterAll |
付与されたメソッドは、1番最後に1度だけ実行される メソッドはstaticである必要がある |
@AfterEach |
付与されたメソッドは、各テストメソッドの後に毎回実行される |
テストグルーピング
package sample.junit5;
import org.junit.jupiter.api.*;
class JUnit5Test {
@Test
void test1() {...}
@Nested
class group1 {
@Test
void test2() {...}
@Test
void test3() {...}
}
}
アノテーション | 説明 |
---|---|
@Nested |
非staticなクラスに付与するとテストクラスを入れ子にできる |
- テストクラスはそれなりのステップ数になることも多いので、テスト観点ごとにグルーピングするのがおすすめです
パラメータテスト
package sample.junit5;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class JUnit5Test {
@ParameterizedTest
@ValueSource(strings = {"foo", "bar", "baz"})
void test(String value) {
System.out.println("VALUE: " + value);
}
}
実行結果
VALUE: foo
VALUE: bar
VALUE: baz
アノテーション | 説明 |
---|---|
@ParameterizedTest |
付与されたメソッドは、パラメータテストになる |
@ValueSource |
リテラル値の配列を1つ指定することができ、パラメータテスト呼び出しで1つのパラメータを提供する(例はString) |
- パラメータの分だけテストが実行されるようなイメージです
- 以下のリテラル値が提供されています
short
byte
int
long
float
double
char
java.lang.String
java.lang.Class
最後に
- すいません、時間がなさすぎて書きたいことの半分も書けてない状態です(...12/18 23時過ぎに書き始めました)
- とにかく言いたいことは、JUnit5は便利で簡単です
- 皆さん、テストコードはちゃんと書きましょう