1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【初心者向け】JUnit 5の使い方を基礎から丁寧に解説(Java)

1
Last updated at Posted at 2024-11-05

はじめに

Javaのテストフレームワーク JUnit 5 の使い方を、基礎から丁寧に解説します。

「テストを書いたことがない」「JUnitって何?」という方でも、この記事を読めば 自分でテストを書いて実行できる ようになります。

JUnitとは

JUnitは、Javaで最も広く使われているテストフレームワーク です。

項目 内容
正式名称 JUnit 5(Jupiter)
用途 ユニットテスト(単体テスト)
メリット コードの品質を保証し、バグを早期に発見できる

参考: JUnit 5 ユーザーガイド(公式)

基本の4ステップ

ステップ1:テスト対象のクラスを作る

まずは、テストしたいクラスを用意します。

package com.example.calculator;

public class Calculator {

    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }

    public int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("0で割ることはできません");
        }
        return a / b;
    }
}

ステップ2:テストクラスを作る

テスト対象クラスに対応するテストクラスを作成します。

package com.example.calculator;

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

class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {
        // 各テストの前にインスタンスを作成
        calculator = new Calculator();
    }

    @Test
    @DisplayName("2 + 3 = 5 になること")
    void testAdd() {
        int result = calculator.add(2, 3);
        assertEquals(5, result, "2 + 3 は 5 になるべき");
    }

    @Test
    @DisplayName("5 - 3 = 2 になること")
    void testSubtract() {
        int result = calculator.subtract(5, 3);
        assertEquals(2, result, "5 - 3 は 2 になるべき");
    }

    @Test
    @DisplayName("4 × 3 = 12 になること")
    void testMultiply() {
        int result = calculator.multiply(4, 3);
        assertEquals(12, result, "4 × 3 は 12 になるべき");
    }

    @Test
    @DisplayName("10 ÷ 2 = 5 になること")
    void testDivide() {
        int result = calculator.divide(10, 2);
        assertEquals(5, result, "10 ÷ 2 は 5 になるべき");
    }

    @Test
    @DisplayName("0で割ると例外が発生すること")
    void testDivideByZero() {
        assertThrows(IllegalArgumentException.class, () -> {
            calculator.divide(10, 0);
        });
    }
}

ステップ3:テストを実行する

IDEで右クリック → 「Run Tests」、またはコマンドラインで実行します。

# Maven
mvn test

# Gradle
gradle test

ステップ4:結果を確認する

✅ testAdd          - PASSED
✅ testSubtract     - PASSED
✅ testMultiply     - PASSED
✅ testDivide       - PASSED
✅ testDivideByZero - PASSED

5 tests completed, 0 failed

全てグリーンになればOKです。失敗したテストがあれば、テスト対象のコードかテストコードを修正しましょう。

テストが失敗する場合

意図的に失敗するテストを書いて、JUnitの出力を確認してみましょう。

@Test
@DisplayName("意図的に失敗させるテスト")
void testAddFail() {
    Calculator calculator = new Calculator();
    int result = calculator.add(8, 3);
    assertEquals(5, result, "8 + 3 の結果が 5 ではないので失敗する");
}

実行結果

❌ testAddFail - FAILED

org.opentest4j.AssertionFailedError: 8 + 3 の結果が 5 ではないので失敗する
Expected: 5
Actual  : 11

JUnitは 期待値(Expected)と実際の値(Actual) を表示してくれるので、何が間違っているかすぐにわかります。

よく使うアノテーション一覧

テスト実行系

アノテーション 用途 実行タイミング
@Test テストメソッドとして認識させる テスト実行時
@DisplayName テスト名を日本語で表示 テスト結果に表示
@Disabled テストを一時的にスキップ 実行しない
@Test
@DisplayName("ユーザー名が空の場合、エラーになること")
void testEmptyUsername() {
    // テストコード
}

@Test
@Disabled("バグ #123 の修正待ち")
void testSomethingBroken() {
    // 一時的にスキップ
}

ライフサイクル系

アノテーション 用途 実行回数
@BeforeEach 各テストのに実行 テストの数だけ
@AfterEach 各テストのに実行 テストの数だけ
@BeforeAll 全テストのに1回だけ実行 1回
@AfterAll 全テストのに1回だけ実行 1回
class UserServiceTest {

    @BeforeAll
    static void initAll() {
        System.out.println("=== テスト開始 ===");
        // DB接続など、重い初期化処理
    }

    @BeforeEach
    void init() {
        System.out.println("--- テストメソッド開始 ---");
        // テストデータの準備
    }

    @AfterEach
    void tearDown() {
        System.out.println("--- テストメソッド終了 ---");
        // テストデータのクリーンアップ
    }

    @AfterAll
    static void tearDownAll() {
        System.out.println("=== テスト終了 ===");
        // DB切断など
    }

    @Test
    void test1() {
        System.out.println("test1 実行中");
    }

    @Test
    void test2() {
        System.out.println("test2 実行中");
    }
}

実行順序

=== テスト開始 ===        ← @BeforeAll
--- テストメソッド開始 --- ← @BeforeEach
test1 実行中              ← @Test
--- テストメソッド終了 --- ← @AfterEach
--- テストメソッド開始 --- ← @BeforeEach
test2 実行中              ← @Test
--- テストメソッド終了 --- ← @AfterEach
=== テスト終了 ===        ← @AfterAll

よく使うアサーション一覧

アサーションは 「期待した結果になっているか」を検証する メソッドです。

基本のアサーション

// 値が等しいか
assertEquals(期待値, 実際の値);
assertEquals(5, calculator.add(2, 3));

// 値が等しくないか
assertNotEquals(0, calculator.add(2, 3));

// trueか
assertTrue(result > 0);

// falseか
assertFalse(list.isEmpty());

// nullか
assertNull(user.getMiddleName());

// nullでないか
assertNotNull(user.getId());

例外のテスト

// 例外が発生することを検証
assertThrows(IllegalArgumentException.class, () -> {
    calculator.divide(10, 0);
});

// 例外メッセージも検証
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
    calculator.divide(10, 0);
});
assertEquals("0で割ることはできません", exception.getMessage());

複数の検証をまとめて実行

// 1つ失敗しても全て実行される
assertAll("ユーザー情報の検証",
    () -> assertEquals("太郎", user.getName()),
    () -> assertEquals("taro@example.com", user.getEmail()),
    () -> assertEquals(25, user.getAge())
);

実践的なテストパターン

パラメータ化テスト

同じテストを複数の値で実行したいときに便利です。

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

class CalculatorTest {

    @ParameterizedTest
    @DisplayName("足し算のパラメータ化テスト")
    @CsvSource({
        "1, 1, 2",
        "2, 3, 5",
        "10, -5, 5",
        "0, 0, 0",
        "-3, -7, -10"
    })
    void testAddParameterized(int a, int b, int expected) {
        Calculator calculator = new Calculator();
        assertEquals(expected, calculator.add(a, b));
    }
}

1つのテストメソッドで 5パターン のテストが実行されます。

ネストテスト

テストをグループ化して整理できます。

@DisplayName("Calculatorのテスト")
class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @Nested
    @DisplayName("addメソッド")
    class AddTest {

        @Test
        @DisplayName("正の数同士の足し算")
        void testPositiveNumbers() {
            assertEquals(5, calculator.add(2, 3));
        }

        @Test
        @DisplayName("負の数を含む足し算")
        void testNegativeNumbers() {
            assertEquals(-1, calculator.add(2, -3));
        }

        @Test
        @DisplayName("0を含む足し算")
        void testWithZero() {
            assertEquals(3, calculator.add(3, 0));
        }
    }

    @Nested
    @DisplayName("divideメソッド")
    class DivideTest {

        @Test
        @DisplayName("正常な割り算")
        void testNormalDivide() {
            assertEquals(5, calculator.divide(10, 2));
        }

        @Test
        @DisplayName("0で割ると例外発生")
        void testDivideByZero() {
            assertThrows(IllegalArgumentException.class, () -> {
                calculator.divide(10, 0);
            });
        }
    }
}

テスト結果がツリー構造で表示され、とても見やすくなります。

Calculatorのテスト
├── addメソッド
│   ├── ✅ 正の数同士の足し算
│   ├── ✅ 負の数を含む足し算
│   └── ✅ 0を含む足し算
└── divideメソッド
    ├── ✅ 正常な割り算
    └── ✅ 0で割ると例外発生

テストを書くときのコツ

1. テストメソッド名は「何をテストしているか」がわかるように

// 悪い例
@Test
void test1() { ... }

// 良い例
@Test
@DisplayName("メールアドレスが空の場合、バリデーションエラーになること")
void testEmailValidation_empty_shouldFail() { ... }

2. 1つのテストで1つのことだけ検証する

// 悪い例:複数のことを1つのテストで検証
@Test
void testCalculator() {
    assertEquals(5, calculator.add(2, 3));
    assertEquals(2, calculator.subtract(5, 3));
    assertEquals(12, calculator.multiply(4, 3));
}

// 良い例:1テスト1検証
@Test
void testAdd() {
    assertEquals(5, calculator.add(2, 3));
}

@Test
void testSubtract() {
    assertEquals(2, calculator.subtract(5, 3));
}

3. テストの構造は「AAA パターン」で書く

@Test
void testUserRegistration() {
    // Arrange(準備)
    UserService service = new UserService();
    String email = "test@example.com";
    String password = "Password1";

    // Act(実行)
    User user = service.register(email, password);

    // Assert(検証)
    assertNotNull(user.getId());
    assertEquals(email, user.getEmail());
}

4. テストは独立させる

各テストが他のテストに依存しないようにしましょう。@BeforeEach で毎回初期化するのがポイントです。

まとめ

カテゴリ 覚えること
基本アノテーション @Test, @DisplayName, @Disabled
ライフサイクル @BeforeEach, @AfterEach, @BeforeAll, @AfterAll
アサーション assertEquals, assertTrue, assertThrows, assertAll
実践テクニック パラメータ化テスト、ネストテスト
書き方のコツ AAAパターン、1テスト1検証、わかりやすい命名

まずは簡単なクラスから 実際にテストを書いてみる ことが一番の学習方法です。

この記事が、JUnitを始めるきっかけになれば嬉しいです!


著者: @kotaro_ai_lab
AI駆動開発やテック情報を毎日発信しています。フォローお気軽にどうぞ!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?