JUnit5はJavaの単体テストで最も使われるフレームワークです。この記事では、JUnit5の導入方法から@Testアノテーション・アサーション・例外テストの基本、さらにMockitoを使ったモックテストまで、サンプルコード付きで解説します。
「テストコードの書き方がわからない」「JUnit4との違いが気になる」という方に向けて、現役エンジニアが実務で使うパターンを交えながら、明日からテストが書ける実践的な内容にまとめました。
この記事でわかること
- JUnit5の導入方法(Maven/Gradle)
- @Test・アサーション・例外テストの基本的な書き方
- Arrange-Act-Assertパターンによるテスト設計
- @BeforeEach・@ParameterizedTest・@Nestedなどの便利機能
- Mockitoを使ったモックテストの基礎
JUnit5とは?Javaテストフレームワークの基本

JUnitは、Javaのユニットテスト(単体テスト)を書いて実行するためのフレームワークです。Javaのテストツールとして最も広く使われています。
JUnitは高品質なソフトウェア開発に欠かせません。 コードが意図通りに動くかを自動で検証でき、バグの早期発見やリファクタリング(コードの改善作業)を支援してくれるからです。
ユニットテストの目的と重要性
ユニットテストの目的は、クラスやメソッドといったプログラムの最小単位(ユニット)が、それぞれ正しく機能するかを検証することにあります。
ユニットテストを導入するメリットは主に3つです。
JUnitの概要とバージョンの違い(JUnit4とJUnit5)
JUnitにはいくつかのバージョンがありますが、現在主流なのはJUnit5です。以前はJUnit4が広く使われていました。
JUnit4とJUnit5では、アーキテクチャとアノテーション名が大きく変わりました。例えば、テスト前の初期化処理は、JUnit4では@Beforeでしたが、JUnit5では@BeforeEachに変わりました。
JUnit5は3つのモジュール(JUnit Platform、JUnit Jupiter、JUnit Vintage)で構成されており、拡張性が大幅に向上しました。2026年現在、次世代のJUnit 6もRC段階に入っていますが、実務ではJUnit5(Jupiter)が標準です。これからJavaのテストを学ぶなら、JUnit5から始めましょう。
JUnit4とJUnit5の主な違いを表にまとめました。
| 項目 | JUnit4 | JUnit5 |
|---|---|---|
| テストアノテーション | @Test(org.junit) | @Test(org.junit.jupiter.api) |
| 初期化 | @Before | @BeforeEach |
| 全体初期化 | @BeforeClass | @BeforeAll |
| 無効化 | @Ignore | @Disabled |
| アーキテクチャ | 単一jar | Platform + Jupiter + Vintage |
| Java最低バージョン | Java 5 | Java 8 |
JUnitの導入方法

JUnitをプロジェクトに導入するのは非常に簡単です。特に、MavenやGradleといったビルドツールを利用すると、数行の設定を追加するだけで済みます。
Maven/Gradleによる導入
最近のJavaプロジェクトでは、依存ライブラリの管理にMavenまたはGradleを使用するのが一般的です。
Mavenの場合 (pom.xml)
pom.xmlファイルの<dependencies>セクションに、以下の依存関係を追加します。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency><scope>test</scope>は、このライブラリがテストコードのコンパイルと実行時にのみ必要であることを示します。JUnit5はJava 8以上で動作しますが、2026年現在はJava 17またはJava 21 LTSでの利用が一般的です。
Gradleの場合 (build.gradle)
build.gradleファイルに以下を記述します。
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.0'
}
test {
useJUnitPlatform()
}IDE(IntelliJ/Eclipse)でのセットアップ
IntelliJ IDEA・Eclipse・VS Code(Extension Pack for Java)などのIDEを使っている場合、さらに簡単です。
プロジェクト作成時のウィザードで「JUnit5」を選ぶだけで、必要な設定は自動で完了します。テストクラスを手動で作る場合も、IDEがJUnitの追加を提案してくれます。
JUnit5の基本的なテストの書き方

JUnitの導入が完了したら、いよいよテストコードを書いていきましょう。ここでは、計算を行うシンプルなCalculatorクラスを例に、基本的なテストの書き方を解説します。
public class Calculator {
public int add(int a, int b) {
return a + b;
}
}@Testアノテーションの使い方
JUnit5では、テストしたいメソッドに@Testアノテーションを付けることで、そのメソッドがテストケースであることをフレームワークに伝えます。
テストクラスは、慣習としてsrc/test/javaディレクトリ配下に作成します。
import org.junit.jupiter.api.Test;
class CalculatorTest {
@Test
void testAdd() {
// ここにテストのロジックを記述する
}
}アサーション(assertEquals / assertTrueなど)
テストコードの核心は「アサーション(Assertion)」、つまりメソッドの実行結果が期待どおりかを検証する仕組みです。JUnit5ではAssertionsクラスのstaticメソッドを使います。
最もよく使われるのが、2つの値が等しいかを確認するassertEqualsです。
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void 足し算が正しくできるか検証する() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 は 5 になるべきです");
}
}assertEqualsは、第1引数に「期待値」、第2引数に「実際の値」を取ります。第3引数は、テストが失敗したときに表示されるメッセージで、省略も可能です。
他にも、以下のような便利なアサーションメソッドがあります。
例外の検証
特定の条件下で、メソッドが正しく例外をスローするかを検証したいケースもあります。JUnit5では、assertThrowsメソッドを使って簡単に例外テストを記述できます。
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class SomeServiceTest {
@Test
void 引数がnullの場合に例外をスローするか() {
SomeService service = new SomeService();
// service.process(null) を実行した際に IllegalArgumentException がスローされることを期待する
assertThrows(IllegalArgumentException.class, () -> {
service.process(null);
});
}
}assertThrowsの第1引数には期待する例外の型、第2引数には例外が出るはずの処理をラムダ式で渡します。意図した例外が正しく発生するかを安全にテストできます。
テストケースの構造と設計

読みやすく保守しやすいテストを書くには、構造と命名が大切です。3つのポイントを紹介します。
Arrange-Act-Assertパターンとは
テストコードはArrange-Act-Assert (AAA) パターンで書くのが効果的です。 テストの目的が明確になり、誰が見てもわかりやすくなります。
Arrange・Act・Assertの3フェーズをコメントや空行で明確に分けることで、テストコードの読みやすさは飛躍的に向上します。
実務でよくある失敗は、1つのテストメソッドに複数のActとAssertを詰め込むことです。テストが失敗したとき、どのActが原因かわからなくなります。1テスト1検証を心がけましょう。
@Test
void 足し算が正しくできるか検証する_AAAパターン() {
// Arrange
Calculator calculator = new Calculator();
int a = 10;
int b = 20;
int expected = 30;
// Act
int actual = calculator.add(a, b);
// Assert
assertEquals(expected, actual);
}テストクラスとテストメソッドの命名規則
テストメソッドの命名で理想的なのは、名前を読むだけで「何を」「どの状況で」「どう検証しているか」がわかることです。
- テストクラス名:
[テスト対象クラス名]Testとするのが一般的です。(例:CalculatorTest) - テストメソッド名: 英語なら
should[期待する結果]When[条件]のような形式があります。日本語なら「〇〇の場合は〇〇を返すこと」のように自然な文章で書くとわかりやすいです。
良い命名は、テストが失敗したときのエラーメッセージを読むだけで、問題の原因を推測する手助けとなります。
筆者のチームでは、日本語メソッド名を採用しています。IDEのテスト結果が一目で読めるため、コードレビューの効率が上がりました。英語名か日本語名かはチームで統一することが大切です。
ユニットテスト(単体テスト)と統合テストの違い
JUnitが得意とする「ユニットテスト(単体テスト)」は、クラスやメソッドなど1つの部品を対象にします。データベースやAPIなど外部への依存を切り離し、対象のロジックだけを検証します。
一方、「統合テスト」は複数のコンポーネントを組み合わせ、連携が正しく動くかを確認します。ControllerからServiceを経由してDBにアクセスする一連の流れが典型例です。
まずはユニットテストをしっかり書くことが、品質保証の第一歩です。
JUnit5の便利なアノテーション

基本をマスターしたら、テストをさらに効率化するアノテーションを使いましょう。
@BeforeEach / @AfterEach(初期化と後処理)
@BeforeEachは、各テストの前に共通の初期化処理を実行するアノテーションです。複数のテストで同じオブジェクト生成が必要なときに役立ちます。
同様に、@AfterEachは各テストメソッドの実行後に呼ばれ、リソースの解放などの後処理に使います。
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
// 各テストの前にCalculatorインスタンスを生成する
this.calculator = new Calculator();
System.out.println("テスト準備完了");
}
@AfterEach
void tearDown() {
// 各テストの後に実行される
System.out.println("テスト後処理完了");
}
@Test
void testAdd() {
assertEquals(5, calculator.add(2, 3));
}
@Test
void testSubtract() {
// assertEquals(1, calculator.subtract(3, 2));
}
}@ParameterizedTestによるパラメータ化テスト
同じロジックのテストを、異なる入力値と期待値で何度も実行したい場合があります。@ParameterizedTestを使うと、テストコードの重複を避けられます。
@ValueSourceを使えば、簡単な値のリストをパラメータとして渡せます。
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
class StringUtilsTest {
@ParameterizedTest
@ValueSource(strings = {"", " ", "\t"})
void 文字列がブランクであるか検証する(String input) {
assertTrue(input.isBlank());
}
}さらに、@CsvSourceを使えば、カンマ区切りの値で複数の引数(入力値と期待値など)を渡すことも可能です。
@DisplayNameでテスト名をわかりやすくする
JUnit5の@DisplayNameアノテーションを使うと、テスト結果のレポートに任意の名前を表示できます。メソッド名が英語でも、レポートには日本語の説明を出せるので便利です。
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@DisplayName("Calculatorクラスのテスト")
class CalculatorTest {
@Test
@DisplayName("2 + 3 = 5 になること")
void testAdd() {
Calculator calculator = new Calculator();
assertEquals(5, calculator.add(2, 3));
}
}テストメソッド名を日本語にする方法もありますが、@DisplayNameを使えばメソッド名は英語の命名規則に従いつつ、レポートだけ日本語にできます。チーム開発ではこちらが推奨されるケースが多いです。
@Nestedによる階層的テスト構造
テスト対象クラスの機能が複雑になると、テストクラスも肥大化しがちです。@Nestedアノテーションを使い、内部クラスでテストをグループ化すると、テストの構造がわかりやすくなります。
class BankAccountTest {
// 口座の初期状態に関するテスト
@Nested
class 初期状態のテスト {
@Test
void 新規口座の残高は0円であること() {
// ...
}
}
// 入金機能に関するテスト
@Nested
class 入金テスト {
@Test
void 正の金額を入金すると残高が増えること() {
// ...
}
@Test
void 負の金額を入金しようとすると例外が発生すること() {
// ...
}
}
}関連するテストをまとめることで、読みやすさが格段に向上します。
Mockitoを使ったモックテスト

実際の開発では、クラスが他のクラスや外部システム(データベース、APIなど)に依存していることがほとんどです。依存先まで含めるとユニットテストの範囲を超えてしまいます。
そこで登場するのが「モック(Mock)」です。モックとは、本物のオブジェクトのふりをする偽物のオブジェクトのこと。Mockitoなどのモックライブラリを使うと、モックを簡単に作成できます。
Mockitoの基本と導入方法
Mockitoは、Javaで最も人気のあるモックライブラリの一つです。Mockitoを使うことで、依存オブジェクトの振る舞いを自由に定義し、テスト対象のロジックだけに集中できます。
導入はJUnitと同様に、ビルドツールに依存関係を追加するだけです。
Mavenの場合 (pom.xml)
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
依存オブジェクトのモック化と検証
例えば、ユーザー情報をUserRepositoryから取得して処理を行うUserServiceをテストしたいとします。
// テスト対象クラス
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public String getUserName(int id) {
User user = repository.findById(id);
if (user != null) {
return user.getName();
}
return "Unknown";
}
}UserRepositoryはデータベースにアクセスするため、ユニットテストではモックに置き換えます。Mockitoを使えば、次のようにテストを書けます。
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class) // Mockito拡張を有効にする
class UserServiceTest {
@Mock // UserRepositoryのモックを作成
private UserRepository mockRepository;
@InjectMocks // モックを注入してUserServiceのインスタンスを生成
private UserService userService;
@Test
void 存在するユーザーIDの場合はユーザー名を返すこと() {
// Arrange: モックの振る舞いを定義
User user = new User(1, "Taro");
// repository.findById(1)が呼ばれたら、作成したuserオブジェクトを返すように設定
when(mockRepository.findById(1)).thenReturn(user);
// Act: テスト対象メソッドを実行
String userName = userService.getUserName(1);
// Assert: 結果を検証
assertEquals("Taro", userName);
// Verify: repository.findById(1)が1回だけ呼ばれたことを検証
verify(mockRepository, times(1)).findById(1);
}
}when(...).thenReturn(...)でモックの振る舞い(スタブ:あらかじめ決めた値を返す設定)を定義し、verify(...)でモックのメソッドが期待通りに呼ばれたかを検証します。モックを使うことで、データベースに接続せずにUserServiceのロジックをテストできました。
モックを使うかどうかの判断基準はシンプルです。テスト対象のロジックに集中したいとき、外部依存(DB・API・ファイルシステム)を切り離すためにモックを使います。逆に、値の変換や計算だけを行うユーティリティクラスには、モックは不要です。
まとめ
JUnitによるユニットテストは、Javaエンジニアの必須スキルです。
JUnitを活用することで得られるメリット
- コードの品質が向上する: 自動化されたテストが、バグの混入を未然に防ぎます。
- 開発速度が上がる: 手動テストの時間を削減し、問題の早期発見により手戻りを減らせます。
- 自信を持って開発できる: テストという安全網があるため、リファクタリングや機能追加を恐れずに行えます。
- 仕様が明確になる: テストコードが、コードの振る舞いを定義するドキュメントとして機能します。
最初はテストコードに時間がかかります。しかし、長期的に見れば、その投資は保守性の高い、堅牢なアプリケーションという形で何倍にもなって返ってきます。
JUnit5の基本を理解したら、次はSpring Boot 3での統合テスト(@SpringBootTest)や、カバレッジ計測ツール(JaCoCo)に挑戦してみてください。