モダンなJavaの書き方③:Unit Test
ユニットテストとは
ユニットテスト(単体テスト)とは、クラスやメソッドの動作を個別に自動で検証するテスト手法です。コードに変更を加えたときに意図しないバグが混入していないかをすぐに確認でき、品質の維持・向上に欠かせません。
Java で最もよく使われるテストフレームワークが JUnit です。現在の主流は JUnit 5(JUnit Jupiter)です。
ユニットテストを書くことで、テストしやすい設計(依存が少なく、責務が明確なクラス)を意識するようになるという副次的な効果もあります。
JUnit 5 のセットアップ
Maven を使うプロジェクトの場合、pom.xml に以下の依存関係を追加します。
pom.xml(Maven の場合)
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
Eclipse や IntelliJ IDEA では、プロジェクトにJUnit 5 ライブラリが含まれている場合、追加設定なしで使えます。
Eclipse の場合:プロジェクトを右クリック → 「ビルド・パス」→「ライブラリーの追加」→「JUnit」を選択することで追加できます。
テスト対象クラスの作成
まずテスト対象となる計算クラスを作成します。
Calculator.java
package sample;
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 double divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("0で割ることはできません");
}
return (double) a / b;
}
}
基本的なテストクラスの書き方
テストクラスは通常 src/test/java ディレクトリに配置し、テスト対象と同じパッケージ名で作成します。
CalculatorTest.java
package sample;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
Calculator calc = new Calculator();
@Test
void 足し算のテスト() {
int result = calc.add(3, 4);
assertEquals(7, result);
}
@Test
void 引き算のテスト() {
assertEquals(2, calc.subtract(5, 3));
}
@Test
void 掛け算のテスト() {
assertEquals(12, calc.multiply(3, 4));
}
@Test
void 割り算のテスト() {
assertEquals(2.5, calc.divide(5, 2));
}
}
JUnit 5 ではテストメソッドに 日本語名 を使えます。テスト内容を説明的な名前にすることで、失敗したときに何のテストかすぐに分かります。
主なアノテーション
| アノテーション | 説明 |
|---|---|
| @Test | テストメソッドであることを示す |
| @BeforeEach | 各テストメソッドの実行前に呼ばれる(初期化処理) |
| @AfterEach | 各テストメソッドの実行後に呼ばれる(後処理) |
| @BeforeAll | テストクラス全体の実行前に1回呼ばれる(static メソッド) |
| @AfterAll | テストクラス全体の実行後に1回呼ばれる(static メソッド) |
| @DisplayName | テストの表示名を指定する |
| @Disabled | そのテストを一時的に無効にする |
@BeforeEach を使った初期化
Java
package sample;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest2 {
Calculator calc;
@BeforeEach
void setUp() {
// 各テストの前にインスタンスを生成する
calc = new Calculator();
}
@Test
void 足し算のテスト() {
assertEquals(7, calc.add(3, 4));
}
@Test
void 引き算のテスト() {
assertEquals(2, calc.subtract(5, 3));
}
}
主なアサーションメソッド
アサーション(assertXxx)は期待値と実際の値を比較して、テストの成否を判定します。
| メソッド | 説明 |
|---|---|
| assertEquals(expected, actual) | 値が等しいことを確認 |
| assertNotEquals(unexpected, actual) | 値が等しくないことを確認 |
| assertTrue(condition) | 条件が true であることを確認 |
| assertFalse(condition) | 条件が false であることを確認 |
| assertNull(object) | null であることを確認 |
| assertNotNull(object) | null でないことを確認 |
| assertThrows(type, executable) | 指定した例外がスローされることを確認 |
| assertAll(executables...) | 複数のアサーションをまとめて実行 |
例外のテスト
assertThrows を使うと、例外が正しくスローされるかをテストできます。
Java
@Test
void ゼロ除算で例外が発生すること() {
// divide(10, 0) が ArithmeticException をスローするか検証
ArithmeticException ex = assertThrows(
ArithmeticException.class,
() -> calc.divide(10, 0)
);
// 例外のメッセージも確認
assertEquals("0で割ることはできません", ex.getMessage());
}
assertAll による複数アサーション
assertAll を使うと、一部のアサーションが失敗しても全件チェックできます。
Java
@Test
void 四則演算をまとめてテスト() {
assertAll("Calculator の四則演算",
() -> assertEquals(7, calc.add(3, 4), "足し算"),
() -> assertEquals(1, calc.subtract(4, 3), "引き算"),
() -> assertEquals(12, calc.multiply(3, 4), "掛け算"),
() -> assertEquals(2.0, calc.divide(6, 3), "割り算")
);
}
実践的なサンプル:文字列クラスのテスト
実務でよくある文字列処理クラスとそのテストの例です。
StringUtils.java
package sample;
public class StringUtils {
// 文字列を逆順にする
public String reverse(String str) {
if (str == null) return null;
return new StringBuilder(str).reverse().toString();
}
// 回文かどうか判定する
public boolean isPalindrome(String str) {
if (str == null) return false;
String s = str.toLowerCase();
return s.equals(new StringBuilder(s).reverse().toString());
}
// 文字数をカウントする(空白を除く)
public int countNonSpace(String str) {
if (str == null) return 0;
return (int) str.chars().filter(c -> c != ' ').count();
}
}
StringUtilsTest.java
package sample;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
@DisplayName("StringUtils のテスト")
class StringUtilsTest {
StringUtils utils;
@BeforeEach
void setUp() {
utils = new StringUtils();
}
@Test
@DisplayName("文字列の逆順")
void reverse_通常の文字列() {
assertEquals("olleh", utils.reverse("hello"));
}
@Test
void reverse_nullを渡すとnullを返す() {
assertNull(utils.reverse(null));
}
@Test
void isPalindrome_回文の場合はtrue() {
assertTrue(utils.isPalindrome("madam"));
assertTrue(utils.isPalindrome("racecar"));
}
@Test
void isPalindrome_回文でない場合はfalse() {
assertFalse(utils.isPalindrome("hello"));
}
@Test
void countNonSpace_空白を除いた文字数を返す() {
assertEquals(5, utils.countNonSpace("hello"));
assertEquals(5, utils.countNonSpace("h e l l o"));
assertEquals(0, utils.countNonSpace(null));
}
}
テストの実行と結果の見方
Eclipse では、テストクラスを右クリック → 「実行」→「JUnit テスト」 で実行します。
JUnit ビューに結果が表示されます。
| 表示 | 意味 |
|---|---|
| 緑のバー / ✓ | テスト成功(PASS) |
| 赤のバー / ✗ | テスト失敗(FAIL)—— アサーションが失敗 |
| ✗(エラー) | テスト中に予期しない例外が発生 |
まとめ
・
・
・
・
・テストメソッド名を日本語にすると、何のテストか一目で分かる
・テストを書く習慣をつけることで、バグの早期発見と安全なリファクタリングが可能になる
・
@Test でテストメソッドを宣言し、assertEquals などで検証する・
@BeforeEach で各テストの前処理(初期化)を共通化する・
assertThrows で例外が正しくスローされるかを検証できる・
assertAll で複数のアサーションをまとめてチェックできる・テストメソッド名を日本語にすると、何のテストか一目で分かる
・テストを書く習慣をつけることで、バグの早期発見と安全なリファクタリングが可能になる