【Java入門】JUnitでテストコードを書こう!基本の使い方を初心者向けに解説

docs

前回はJUnitの基本的な考え方について解説しました(テスト駆動開発 (TDD) ってなに? | ToolDocs)。今回は、実際にテストコードを書いて、JUnitをもっと深く理解していきましょう。

テスト対象のクラスを用意しよう

まずはテストしたいクラスを用意します。今回は簡単な足し算と引き算ができるCalculatorクラスを例にします。

Java

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

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

テストクラスを作成しよう

次に、このCalculatorクラスをテストするためのクラスを作成します。テストクラスは、テストしたいクラス名にTestをつけた名前にするのが一般的です。今回はCalculatorTestとします。

Java

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

public class CalculatorTest {

    // ここにテストメソッドを書いていきます

}

import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.*;は忘れずに記述しましょう。@Testアノテーションは、そのメソッドがテストメソッドであることをJUnitに教えてくれます。Assertionsクラスは、テストの結果を検証するための便利なメソッドを提供してくれます。

テストメソッドを書いてみよう

それでは、Calculatorクラスのaddメソッドをテストするメソッドを書いてみましょう。

Java

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

public class CalculatorTest {

    @Test
    void testAdd() {
        Calculator calculator = new Calculator();
        int expected = 5;
        int actual = calculator.add(2, 3);
        assertEquals(expected, actual);
    }
}

解説

  • @Testアノテーションをメソッドの頭につけることで、このメソッドがテストとして実行されるようになります。
  • testAdd()は、addメソッドをテストしていることを表すメソッド名です。テストメソッド名はtestから始めるのが慣例です。
  • Calculator calculator = new Calculator();で、テスト対象のインスタンスを作成します。
  • int expected = 5;で、期待する結果を定義します。
  • int actual = calculator.add(2, 3);で、実際の計算結果を取得します。
  • assertEquals(expected, actual);アサーション と呼ばれる部分です。これは「actualexpectedと同じであることを確認する」という意味になります。もし違っていれば、テストは失敗します。

実行結果

このテストを実行すると、特にエラーメッセージが出なければテストは成功です。多くのIDE(統合開発環境)では、緑色のチェックマークなどで成功を示してくれます。


別のテストメソッドも書いてみよう

今度はsubtractメソッドもテストしてみましょう。

Java

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

public class CalculatorTest {

    @Test
    void testAdd() {
        Calculator calculator = new Calculator();
        int expected = 5;
        int actual = calculator.add(2, 3);
        assertEquals(expected, actual);
    }

    @Test
    void testSubtract() {
        Calculator calculator = new Calculator();
        int expected = 1;
        int actual = calculator.subtract(5, 4);
        assertEquals(expected, actual);
    }
}

実行結果

こちらも特にエラーがなければ成功です。


複数のパターンをテストしてみよう

addメソッドは、負の数やゼロが含まれる場合も正しく動作するでしょうか?複数のパターンをテストしてみることは非常に重要です。

Java

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

public class CalculatorTest {

    @Test
    void testAddPositiveNumbers() {
        Calculator calculator = new Calculator();
        assertEquals(5, calculator.add(2, 3));
    }

    @Test
    void testAddNegativeNumbers() {
        Calculator calculator = new Calculator();
        assertEquals(-5, calculator.add(-2, -3));
    }

    @Test
    void testAddPositiveAndNegative() {
        Calculator calculator = new Calculator();
        assertEquals(1, calculator.add(5, -4));
    }

    @Test
    void testAddZero() {
        Calculator calculator = new Calculator();
        assertEquals(0, calculator.add(0, 0));
        assertEquals(5, calculator.add(5, 0));
        assertEquals(-5, calculator.add(-5, 0));
    }

    @Test
    void testSubtract() {
        Calculator calculator = new Calculator();
        assertEquals(1, calculator.subtract(5, 4));
        assertEquals(-1, calculator.subtract(4, 5));
        assertEquals(7, calculator.subtract(3, -4)); // 3 - (-4) = 7
    }
}

解説

それぞれのテストメソッドで、特定の条件下でのaddメソッドの挙動を検証しています。testAddZeroのように、一つのテストメソッド内で複数のアサーションを行うことも可能です。

実行結果

すべてのテストが成功すれば、Calculatorクラスのaddメソッドとsubtractメソッドは、少なくともこれらの入力パターンでは正しく動作すると言えます。


テストが失敗する例を見てみよう

もし、addメソッドにバグがあったらどうなるでしょうか?例えば、誤って引き算をしてしまうようなバグを仕込んでみましょう。

Java

// わざとバグを仕込んだCalculatorクラス
public class Calculator {
    public int add(int a, int b) {
        return a - b; // わざと引き算にしてみる
    }

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

この状態でtestAddPositiveNumbersを実行するとどうなるでしょう?

Java

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

public class CalculatorTest {

    @Test
    void testAddPositiveNumbers() {
        Calculator calculator = new Calculator();
        assertEquals(5, calculator.add(2, 3)); // ここが失敗する
    }

    // 他のテストメソッドは省略
}

実行結果

テストが失敗し、以下のようなメッセージが表示されます(IDEやJUnitのバージョンによって多少異なります)。

org.opentest4j.AssertionFailedError:
Expected :5
Actual   :-1

これは、「期待していた結果は5だったのに、実際の結果は-1でしたよ」ということを示しています。このように、テストが失敗することで、どこにバグがあるのかを特定しやすくなります。


他のアサーションメソッド

assertEquals以外にも、JUnitにはさまざまなアサーションメソッドがあります。よく使うものをいくつか紹介します。

  • assertTrue(boolean condition): 条件がtrueであることを確認します。
  • assertFalse(boolean condition): 条件がfalseであることを確認します。
  • assertNull(Object object): オブジェクトがnullであることを確認します。
  • assertNotNull(Object object): オブジェクトがnullではないことを確認します。
  • assertThrows(Class<? extends Throwable> expectedType, Executable executable): 特定の例外がスローされることを確認します。

assertThrowsの例

例えば、ゼロで割り算をしようとするとArithmeticExceptionがスローされるようなdivideメソッドがあったとします。

Java

public class Calculator {
    // ... 既存のメソッド ...

    public int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        return a / b;
    }
}

このdivideメソッドがゼロ除算のときに正しく例外をスローするかテストするには、assertThrowsを使います。

Java

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

public class CalculatorTest {
    // ... 既存のテストメソッド ...

    @Test
    void testDivideByZeroThrowsException() {
        Calculator calculator = new Calculator();
        // 第1引数に期待する例外のクラス、第2引数に例外を発生させる処理を書く
        assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0));
    }
}

実行結果

このテストを実行すると、ArithmeticExceptionがスローされるため、テストは成功します。もしArithmeticExceptionがスローされなかったら、テストは失敗します。


まとめ

今回はJUnitを使って実際にテストコードを書いてみました。

  • テスト対象のクラスとテストクラスを用意する。
  • @Testアノテーションをつけてテストメソッドを作成する。
  • assertEqualsなどの アサーションメソッド を使って結果を検証する。
  • テストが失敗した時のエラーメッセージからバグを特定する。
  • 様々なアサーションメソッドを使いこなす。

これであなたもJUnitの基本をマスターしたはずです!次回は、もっと実践的なテストの書き方や、テストを効率的に実行する方法について掘り下げていきます。お楽しみに!

引き続き学習したい方はこちらから! -> ToolDocs | 様々なツールや技術情報を紹介します

コメント

タイトルとURLをコピーしました