JUnit 5を学び始めると、最初に迷いやすいのが「どのアサーションを使えばよいのか」と「どのアノテーションを覚えればよいのか」です。

この記事では、Javaのテストコードでよく使うJUnit 5のアサーションとアノテーションを、実務で使う場面に寄せて整理します。

結論

最初に押さえるなら、次のアサーションとアノテーションで十分です。

  • assertEquals: 期待値と実際の値が同じか確認する
  • assertTrue / assertFalse: 条件がtrue/falseか確認する
  • assertNull / assertNotNull: nullかどうか確認する
  • assertThrows: 例外が発生することを確認する
  • assertAll: 複数の確認をまとめて実行する
  • @Test: テストメソッドとして実行する
  • @BeforeEach / @AfterEach: 各テストの前後処理を定義する
  • @Nested: テストを内側のクラスで整理する
  • @ParameterizedTest: 複数パターンの入力で同じテストを実行する

JUnit 5は機能が多いですが、最初から全部を覚える必要はありません。まずは「何を確認したいテストなのか」を言葉にして、それに合うアサーションを選ぶのが大事です。

JUnit 5の基本準備

テストコードでは、JUnit 5のアサーションをstatic importしておくと読みやすくなります。

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class CalculatorTest {

    @Test
    void add_2つの数値を足し算できること() {
        Calculator calculator = new Calculator();

        int actual = calculator.add(2, 3);

        assertEquals(5, actual);
    }
}

assertEqualsは、基本的に assertEquals(expected, actual) の順番で書きます。つまり、先に期待値、後に実際の値です。

assertEquals: 値が一致することを確認する

assertEqualsは、期待した値と実際の値が一致することを確認するときに使います。

@Test
void 税込価格を計算できること() {
    int price = 1000;
    int actual = price + 100;

    assertEquals(1100, actual);
}

失敗時のメッセージを付けたい場合は、最後の引数に書きます。

assertEquals(1100, actual, "税込価格が想定と異なります");

メッセージは必須ではありませんが、計算式や条件が複雑なテストでは付けておくと原因を追いやすくなります。

assertTrue / assertFalse: 条件を確認する

assertTrueは条件がtrueであること、assertFalseは条件がfalseであることを確認します。

@Test
void 在庫がある場合は購入可能であること() {
    Stock stock = new Stock(10);

    assertTrue(stock.canPurchase(1));
    assertFalse(stock.canPurchase(100));
}

ただし、何でも assertTrue で書くと、失敗したときに原因が分かりにくくなります。

// 原因が少し分かりにくい
assertTrue(actual == 1100);

// 期待値と実際の値が分かりやすい
assertEquals(1100, actual);

値の比較なら assertEquals、条件そのものを確認したいなら assertTrue / assertFalse と考えると整理しやすいです。

assertNull / assertNotNull: nullを確認する

戻り値がnullであること、またはnullではないことを確認したい場合は、assertNullassertNotNull を使います。

@Test
void IDでユーザーを検索できること() {
    User user = userRepository.findById(1);

    assertNotNull(user);
    assertEquals("yama", user.getName());
}

assertNotNull の後に値の中身を確認すると、テストの意図が読みやすくなります。

assertThrows: 例外が発生することを確認する

不正な入力を渡したときに例外が発生することを確認する場合は、assertThrows を使います。

@Test
void 金額がマイナスの場合は例外になること() {
    Price price = new Price();

    IllegalArgumentException exception = assertThrows(
            IllegalArgumentException.class,
            () -> price.calculateTax(-100)
    );

    assertEquals("金額は0以上で指定してください", exception.getMessage());
}

assertThrows は発生した例外オブジェクトを返します。そのため、例外メッセージや例外に含まれる値を追加で確認できます。

assertDoesNotThrow: 例外が発生しないことを確認する

正常系で例外が発生しないことを明示したい場合は、assertDoesNotThrow を使えます。

@Test
void 正常な金額なら例外が発生しないこと() {
    Price price = new Price();

    assertDoesNotThrow(() -> price.calculateTax(1000));
}

ただし、戻り値を確認できる場合は、例外が出ないことだけでなく、結果も確認した方がテストとして有効です。

assertAll: 複数の確認をまとめる

1つの対象に対して複数の値を確認したい場合は、assertAll が便利です。

@Test
void ユーザー情報を取得できること() {
    User user = userService.findById(1);

    assertAll(
            () -> assertEquals(1, user.getId()),
            () -> assertEquals("yama", user.getName()),
            () -> assertEquals("yama@example.com", user.getEmail())
    );
}

通常のアサーションを続けて書くと、最初に失敗したところでテストが止まります。assertAll を使うと、複数の確認をまとめて実行し、失敗した内容をまとめて確認できます。

@Test: テストメソッドとして実行する

JUnit 5では、テストとして実行したいメソッドに @Test を付けます。

import org.junit.jupiter.api.Test;

class UserServiceTest {

    @Test
    void ユーザーを登録できること() {
        // テスト処理を書く
    }
}

メソッド名は日本語でも書けます。チームの方針にもよりますが、学習段階では「何を確認しているのか」が読みやすい名前にするのがおすすめです。

@BeforeEach / @AfterEach: テスト前後の処理を書く

各テストの前に共通の準備をしたい場合は @BeforeEach、各テストの後に後片付けをしたい場合は @AfterEach を使います。

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class UserServiceTest {

    private UserService userService;

    @BeforeEach
    void setUp() {
        userService = new UserService();
    }

    @Test
    void ユーザーを取得できること() {
        User user = userService.findById(1);

        assertNotNull(user);
    }
}

同じ準備処理を各テストに何度も書いている場合は、@BeforeEach に切り出せないかを考えるとよいです。

@Nested: テストをグループ化する

条件ごとにテストを整理したい場合は、@Nested を使います。

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

class PriceServiceTest {

    @Nested
    class 正常な金額の場合 {

        @Test
        void 税込価格を計算できること() {
            // 正常系のテスト
        }
    }

    @Nested
    class 不正な金額の場合 {

        @Test
        void 例外が発生すること() {
            // 異常系のテスト
        }
    }
}

正常系、異常系、境界値などを分けると、テストクラス全体の見通しがよくなります。

@ParameterizedTest: 複数パターンで同じテストを実行する

同じ処理を複数の入力値で確認したい場合は、@ParameterizedTest を使います。

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class UserNameTest {

    @ParameterizedTest
    @ValueSource(strings = {"yama", "koala", "java"})
    void ユーザー名が空でなければ有効であること(String name) {
        assertTrue(name.length() > 0);
    }
}

@ParameterizedTest を使う場合は、環境によって junit-jupiter-params の依存関係が必要です。Spring Bootのテスト環境では依存関係に含まれていることもありますが、使えない場合は依存関係を確認してください。

アサーションを選ぶときの考え方

JUnitのアサーションは、書き方を暗記するよりも「何を確認したいのか」から選ぶ方が使いやすいです。

確認したいこと 使いやすいアサーション
値が同じか assertEquals
条件がtrue/falseか assertTrue / assertFalse
nullかどうか assertNull / assertNotNull
例外が発生するか assertThrows
複数の値をまとめて確認したい assertAll

まとめ

JUnit 5のアサーションとアノテーションは数が多いですが、最初に押さえる範囲はそれほど広くありません。

まずは assertEqualsassertTrueassertThrows@Test@BeforeEach あたりから使い始めると、基本的なテストコードを書けるようになります。

そのうえで、テストが増えてきたら @Nested@ParameterizedTest を使って、読みやすく整理していくのがよいです。


JUnit 5、Mockito、Spring Boot、DBUnit、Spring Batchのテストを体系的に学びたい方向けに、UdemyでJavaテスト実装の講座も作っています。

基礎的なアサーションから、Mockitoを使ったモック、Spring BootのController/Repositoryテスト、DBUnit、Spring Batchのテストまで順番に学べる内容です。

講座はこちらです。
JUnit 5完全攻略: Javaのテスト実装を基礎から実務レベルまで学ぶ

参考: JUnit 5 User Guide