はじめに
Javaでプログラムを書くとき、単体テストはメソッド単位の不具合を早い段階で見つけるための実装習慣になります。初心者向けの学習では、文法だけを覚えるよりも、入力と期待値を並べて確認する流れまで押さえるほうが理解しやすくなります。
この記事相当の解説記事では、Javaの基本構文、JUnitによる単体テスト、Mockitoを使った依存関係の切り離し、テストケース作成の考え方を順に扱いるのが目安です。サンプルコードは学習用の最小構成に絞り、結果欄では動作未確認の断定を避けて期待される出力として記載します。
そのため、Javaの文法にまだ慣れていない段階でも、プログラムの部品をどのように検証するのかを読み取れます。単体テストの注意点やカスタマイズ方法、応用例まで含めて、初心者向けの実装手順として整理するのがポイントです。
- Java 21 LTS
- JUnit Jupiter 5.10系
- Mockito 5系
- Maven 3.9系またはGradle 8系のJavaプロジェクト
- Javaプログラムの基本構文とメソッドの読み方
- JUnitを使った単体テストの最小構成
- テストケース作成で押さえる正常系と異常系
- Mockitoを使うカスタマイズ方法と依存関係の扱い
- 単体テストの注意点と応用例の考え方
Javaとは
Javaはクラスを中心にプログラムを組み立てるオブジェクト指向言語です。公式ドキュメントによれば、Java SEには言語仕様、標準ライブラリ、仮想マシン上で動く実行環境が含まれます。詳しい仕様はJava SE 21 API Specificationで確認できます。
一般にJavaのコードは.javaファイルへ書き、javacでコンパイルして.classファイルに変換するのが一般的です。この仕組みにより、同じプログラムを複数の環境で扱いやすくなります。ただし、開発環境ごとのJDKバージョン差には注意点があるのが基本です。
| 項目 | 主な役割 | 初心者向けの見方 | 単体テストとの関係 |
|---|---|---|---|
class | 処理とデータをまとめる | Javaの基本単位として読む | テスト対象のまとまりになる |
main | プログラム開始点を表す | 最初に呼ばれる入口として見る | 単体テストでは直接使わない場合が多い |
method | 処理を名前付きで分ける | 入力と戻り値を確認する | テストケース作成の中心になる |
int | 整数を扱う | 計算例で使いやすい | assertEqualsで比較しやすい |
String | 文字列を扱う | 表示や名前に使う | 期待値の比較対象になる |
boolean | 真偽値を扱う | 条件分岐と相性がよい | 条件判定の検証に使う |
if | 条件で処理を分ける | 分岐ごとに読む | 正常系と異常系を分ける |
for | 繰り返しを扱う | 回数と終了条件を見る | 境界値の確認に関係する |
@Test | テストメソッドを示す | JUnitの目印として読む | 単体テストを実行対象にする |
assertEquals | 期待値と実値を比較する | 左に期待値、右に実値を置く | サンプルコードで多用される |
assertThrows | 例外発生を確認する | 異常系を表す | 注意点の確認に使う |
mock | 代替オブジェクトを作る | 外部依存を置き換える | Mockitoの応用例で使う |
基本構文
Javaの最小プログラムは、public classでクラスを作り、public static void mainの中に処理を書きます。初心者がつまずきやすいのは、ファイル名とクラス名の対応、波括弧{}の閉じ忘れ、文末の;です。
具体的には、HelloWorldというクラス名なら、通常はHelloWorld.javaというファイル名で保存します。その関係が崩れるとコンパイル時にエラーになりやすいため、最初のサンプルコードでは名前をそろえて読むのが現実的です。
結果: 期待される出力はHello, World!です。
このサンプルコードでは、System.out.printlnがコンソールへ文字列を出す役割を持ちますし、ここがポイントです。単体テストでは画面表示そのものよりも、表示に使う値を返すメソッドへ分けると検証しやすくなります。
データ型と変数
Javaでは、値の種類に応じてint、double、char、boolean、Stringなどを使い分けます。変数は値に名前を付ける仕組みであり、プログラムの途中で計算結果や判定結果を保持するのが現実的です。
これらの型は単体テストでも頻繁に登場します。数値なら計算結果、文字列ならメッセージ、真偽値なら判定結果をassertEqualsやassertTrueで比較する流れになります。
結果: 期待される状態は、numberに10、decimalに20.5、letterにA、flagにtrueが入ることです。
そのため、テストケース作成では入力値の型と期待値の型をそろえる必要があります。たとえばdoubleの比較では丸め誤差を考慮し、JUnitのassertEquals(double expected, double actual, double delta)のような形を選ぶ場合があります。
制御構造
Javaの制御構造にはif、else、switch、for、whileがあると整理できます。条件分岐や繰り返しが入るプログラムは、通る経路ごとに期待値が変わるため、単体テストの設計対象になりやすいです。
このとき、正常な入力だけでなく、境界値や空値に近い条件も確認します。初心者向けの学習では、number > 10、number == 10、number < 10のように条件を分けると、テストケース作成の意図が見えやすくなります。
結果: numberが10の場合、期待される出力はnumberは10以下と、これは0回目のループですからこれは4回目のループですまでの行です。
一方、単体テストではSystem.out.printlnを直接検査するより、判定結果を文字列として返すメソッドへ切り出すほうが扱いやすくなります。Javaの制御構造をメソッド化すると、入力と期待値の組み合わせを明確にできます。
関数とメソッド
Javaでは、クラス内に定義する処理のまとまりをメソッドと呼びますが、これは押さえたい点です。public、static、intなどのキーワードにより、呼び出し方、戻り値の型、利用できる範囲が決まります。
具体的には、計算処理をaddNumbersのようなメソッドへ分離すると、単体テストで入力と戻り値だけを確認できます。プログラム全体を起動しなくても小さな部品を検証できる点が、Javaの単体テストと相性のよい部分です。
結果: 期待される出力は結果は 7 ですです。
この形なら、mainは表示の入口、addNumbersは計算の本体として分けて読めます。単体テストではaddNumbers(3, 4)の戻り値が7になるかを検証すれば、表示処理に依存しない確認になります。
Javaの基本をさらに広げる場合は、内部リンクのJava List型完全ガイドでコレクション、Javaでマスターするオーバーライド解説で継承まわりを確認できると理解できます。単体テストのサンプルコードでも、リストや継承を扱う場面はよくあります。
単体テストとは
単体テストは、プログラムの一部であるメソッドやクラスが期待どおりに動くかを確認するテストです。JavaではJUnitを使う構成が一般的で、@Testを付けたメソッドに検証処理を書きます。
最初に押さえたい結論は、単体テストでは「入力」「処理」「期待値」を明確に分けることです。たとえばadd(2, 3)の戻り値が5になるかを確認するなら、テストケース作成の目的が読み手にも伝わりますし、これが一つの目安です。
単体テストの役割
単体テストは、プログラム全体の画面遷移や外部接続ではなく、小さな処理単位を対象にします。そのため、不具合が起きたときに原因となるメソッドを追いやすくなります。
ただし、単体テストだけで品質をすべて保証できるわけではありません。結合テスト、システムテスト、手動確認と役割を分け、Javaの単体テストはメソッド単位の期待値確認に集中させるのが基本になると覚えるとよいでしょう。
公式のJUnit User Guideでは、@Test、@BeforeEach、@AfterEach、Assertionsなどの使い方が整理されています。詳細はJUnit 5 User Guideが一次情報として参考になります。
単体テストの基本フロー
単体テストの流れは、仕様の確認、テストケース作成、テストコードの記述、結果の確認という順序で進めますが、覚えておくと役立つでしょう。手順という言葉だけで覚えるより、対象メソッドにどんな入力を与え、どんな戻り値を期待するかへ落とし込むと理解しやすいです。
- テスト対象のメソッド名、引数、戻り値を確認します。
- 正常系、境界値、異常系に分けて期待値を決めます。
- JUnitの
@TestメソッドにassertEqualsやassertThrowsを書きますし、ここを基本と考えるとよいでしょう。 - 失敗時のメッセージから、プログラム側かテスト側のどちらを直すか判断します。
こうした流れを押さえると、初心者向けの簡単な計算プログラムでも、テストケース作成の考え方を学べます。次のサンプルコードは、CalculatorのaddメソッドをJUnitで確認する例です。
結果: 期待されるテスト結果は、add(2, 3)の戻り値が5として扱われ、assertEqualsの検証を通過することです。
このサンプルコードでは、Calculatorを生成し、addの戻り値をresultに入れています。その値をassertEquals(5, result)で比較するため、期待値と実際の戻り値の対応が読み取りやすくなります。
Javaでの単体テストの作り方
Javaで単体テストを書く場合、テスト対象のプログラムとテストコードを分けて管理すると考えられます。Mavenなら一般的にsrc/main/javaへ本体、src/test/javaへテストを置きます。
その構成にすると、アプリケーション本体と検証用コードの責務が分かれます。初心者向けには、最初から大きな設計を目指すより、計算メソッドのような小さな対象でテストケース作成に慣れるほうが進めやすくなると言えるでしょう。
テスト計画の作成
テスト計画では、どのメソッドを確認し、どの条件を対象外にするかを決めます。対象範囲が曖昧なままサンプルコードを書き始めると、単体テストと結合テストが混ざりやすくなります。
具体的には、Calculator.addなら整数の加算、負数の加算、ゼロとの加算を候補にできるのが基本です。一方、画面表示やファイル出力は別の層に分けると、Javaのテストコードが読みやすくなります。
テストケースの設計
テストケース作成では、入力値、期待値、確認したい理由をそろえます。単に数を増やすのではなく、仕様上意味のある条件を選ぶほうが、保守しやすい単体テストになるのが目安です。
たとえば加算なら、2 + 3、-2 + 3、0 + 0のように性質の違う値を選びます。これにより、同じような確認を重ねるだけのプログラムにならず、注意点も明確になります。
テストコードの記述
テストコードでは、@Testを付けたメソッド内でテスト対象を準備し、対象メソッドを呼び出し、Assertionsで結果を検証するのがポイントです。JavaのJUnitでは、この配置が読みやすい単体テストの基本形になります。
ただし、テストコードに複雑な条件分岐を入れすぎると、テスト自体の正しさが追いにくくなります。テストケース作成の段階で条件を分け、サンプルコードでは検証意図が見える名前を付けるのが扱いやすいです。
JUnitを使用したサンプルコード
JUnitを使うサンプルコードでは、org.junit.jupiter.api.TestとassertEqualsを読み込みますし、ここがポイントです。Javaの単体テストとして最小限の構成にすると、初心者向けでも検証の流れを追いやすくなります。
結果: 期待されるテスト結果は、resultが5になり、失敗時メッセージとして2 + 3 should be equal to 5が利用されることです。
この例では、Calculatorのaddを呼び出し、戻り値をassertEqualsで比較しています。失敗時メッセージは、期待値と異なる場合に原因を読む手がかりになります。
💡 Tips: テスト名はtestAdditionのような一般名でも動きますが、実務的な解説記事ではadd_returnsSum_whenTwoIntegersGivenのように条件と期待値が伝わる名前も使われますが、これは押さえたい点です。
Mockitoを使用したサンプルコード
Mockitoは、データベースや外部APIのような依存先をモックに置き換えるためのライブラリです。公式情報はMockito公式サイトで確認できます。
その仕組みを使うと、UserServiceのロジックだけを確認し、UserRepositoryの実装詳細から切り離せます。カスタマイズ方法としてよく使われるのは、mock、when、thenReturnの組み合わせです。
結果: 期待されるテスト結果は、findUserById(1)がnew User(1, "John")を返す前提で、getUser(1)の戻り値が期待値と一致することです。
このサンプルコードでは、UserRepositoryを実体ではなくモックとして扱います。ただし、UserでequalsとhashCodeが適切に定義されていない場合、値が同じでもassertEqualsが失敗する可能性があります。
Javaの補助知識として、アノテーションに関する理解はJavaアノテーションの解説記事が参考になるのが一般的です。JUnitの@TestやMockitoの@Mockを読む場面で、アノテーションの役割を理解していると単体テストの見通しがよくなります。
単体テストの注意点
単体テストの注意点は、テストを書く量ではなく、失敗したときに原因を判断できる形へ整えることです。Javaのプログラムでは、対象メソッド、入力、期待値、依存関係を分けておくと、変更時の影響を読み取りやすくなります。
一方、すべての行を無理に検証しようとすると、仕様変更のたびにテストが過剰に壊れますし、これが一つの目安です。初心者向けには、公開メソッドの振る舞い、境界値、例外の条件を中心に設計するのが現実的です。
適切なテストケースの選定
適切なテストケース作成では、正常系だけでなく異常系も含めます。特に押さえたいのは、仕様で許される最小値、最大値、空値、例外になる条件です。
- 仕様に書かれている入力範囲を確認します。
- 利用頻度が高い処理と失敗時の影響が大きい処理を優先するのが現実的です。
- 正常系、境界値、異常系を分けて期待値を決めます。
- 似た条件の重複を避け、読み返せるテスト名を付けます。
具体的には、additionが数値だけを受け付ける仕様なら、addition(2, 3)の成功例と、nullを渡した場合の例外を分けますが、覚えておくと役立つでしょう。この分け方により、プログラムの正常な振る舞いとエラー処理を別々に確認できます。
結果: 期待されるテスト結果は、addition(2, 3)が5と一致し、addition(null, 3)ではIllegalArgumentExceptionとInvalid inputが確認対象になることです。
ただし、このサンプルコードはadditionメソッド本体を省略しています。Javaで実際にコンパイルするには、nullを受け取れる引数型としてIntegerを使うなど、対象プログラム側の定義も合わせる必要があります。
テストコードの保守性
テストコードもプログラムの一部であり、読みやすさと変更しやすさが求められますし、ここを基本と考えるとよいでしょう。テストケース作成の意図が名前や期待値から分からない場合、仕様変更時に残すべき検証か削るべき検証か判断しにくくなります。
そのため、準備処理が重複する場合は@BeforeEachで共通化し、期待値の意味が曖昧な数値には名前を付けます。ただし、共通化しすぎると各テストの前提が見えにくくなるため、サンプルコードでは最小限に抑えるのが扱いやすいです。
- テスト名から条件と期待値を読めるようにすると整理できます。
- 共通の準備処理は必要な範囲だけまとめます。
- 外部依存はモックやテスト用実装へ切り替えます。
- 失敗時メッセージに、何が違うのかを残すると理解できます。
結果: 期待されるテスト結果は、subtraction(5, 3)が2と一致し、subtraction(null, b)でInvalid inputを持つ例外が検証対象になることです。
この例も、subtractionの本体が別に定義されている前提です。Javaの引数にnullを渡すなら、intではなくIntegerなどの参照型を使う必要があり、この点は初心者向けの注意点として覚えておくとよいです。
Thread.sleepや現在時刻へ直接依存すると、環境によって成功と失敗が変わる不安定な単体テストになりやすいです。時刻や乱数は注入できる形にして、期待値を固定できる設計へ寄せます。関連する条件分岐の例として、日付判定を扱うJavaでうるう年を判定する解説記事も参考になります。うるう年のような境界条件は、単体テストの題材としてプログラムの分岐を理解しやすいです。
カスタマイズ方法
カスタマイズ方法として最初に考えるのは、テスト環境、依存ライブラリ、テストデータ、失敗時メッセージの整え方です。Javaの単体テストは、JUnitだけでも書けますが、依存関係が増えるとMockitoやビルドツール設定が関係すると覚えるとよいでしょう。
そのため、初心者向けにはpom.xmlやbuild.gradleで依存関係を固定し、チームや学習環境で同じ結果を得やすくする構成が向いています。プログラム本体とテストコードの場所をそろえるだけでも、サンプルコードの再利用が楽になります。
テスト環境の構築
テスト環境では、JDK、ビルドツール、JUnit、必要に応じてMockitoをそろえますし、ここがポイントです。IDEはIntelliJ IDEA、Eclipse、Visual Studio Codeなどを使えますが、依存関係の解決はMavenやGradleに任せると管理しやすくなります。
JDKをインストールし、java -versionで利用するバージョンを確認します。src/main/javaとsrc/test/javaを分けてJavaプロジェクトを作りますが、これは押さえたい点です。- JUnit Jupiterをテスト依存として追加します。
- 外部依存を切り離す必要がある場合はMockitoを追加します。
具体的なカスタマイズ方法では、テストデータを固定することも大切です。データベースや外部APIに直接つなぐと単体テストの範囲を超えやすいため、メモリ上のデータやモックを使って条件を制御すると考えられます。
結果: 期待されるテスト結果は、Calculator.add(2, 3)の戻り値が5になり、期待値との比較を通過することです。
このサンプルコードは、テスト対象のCalculatorとテストクラスを同じ例の中に置いています。学習段階では読みやすい構成ですが、実際のJavaプロジェクトでは本体とテストを別ファイルへ分けるほうが保守しやすくなります。
失敗時メッセージとデータの調整
失敗時メッセージは、単体テストが落ちた理由を読み解くための補助になると言えるでしょう。assertEqualsの第3引数に説明を入れると、期待値と実値の差だけでは分かりにくい仕様意図を残せます。
一方、メッセージへ長い説明を書きすぎると、テストコードが読みづらくなります。カスタマイズ方法としては、テスト名で条件を示し、メッセージでは仕様上の期待だけを短く補足する程度が扱いやすいです。
privateメソッドを直接検証したくなる場合があるのが基本です。ただし、一般的には公開メソッドの振る舞いを通じて確認し、内部実装へ過度に依存しない形にします。文字列処理を扱う場合は、エスケープや改行の違いも注意点になります。関連する基礎として、Javaエスケープ処理の解説記事を読むと、nや"を期待値へ入れる場面を整理できるのが目安です。
単体テストの応用例
単体テストの応用例では、条件の多いメソッド、依存先を持つサービス、複数データをまとめて検証する処理が対象になります。Javaのプログラムが大きくなるほど、テスト対象を小さく切り出す設計が効いてきます。
これらの応用例では、JUnitの@ParameterizedTest、Mockitoのverify、例外確認のassertThrowsなどを使う場面があるのがポイントです。ただし、初心者向けの段階では、まず通常の@Testで入力と期待値を正確に書けることを優先します。
高度なテストシナリオの作成
高度なテストシナリオでは、複数の条件を組み合わせてプログラムの振る舞いを確認します。たとえばユーザー種別、入力値、権限、状態の組み合わせにより、戻り値や例外が変わる設計があるのが一般的です。
ただし、組み合わせを無制限に増やすと単体テストの見通しが悪くなります。応用例として扱う場合でも、代表値、境界値、失敗条件を選び、同じ意味のケースを重複させないことが注意点になります。
サンプルコードとその説明
サンプルコードでは、JUnitだけで確認できる単純な例と、Mockitoで依存先を置き換える例を分けて扱いるのが現実的です。単体テストの応用例を読むときは、どのクラスがテスト対象で、どのクラスが置き換え対象なのかを先に確認します。
JUnitを使用したサンプルコード
JUnitの応用例でも、基本形は大きく変わりません。Calculatorのような小さなクラスを対象にすると、Javaの単体テストで期待値を比較する流れが明確になります。
結果: 期待されるテスト結果は、testAdd内のresultが5となり、2 + 3 should equal 5の検証条件を満たすことです。
このサンプルコードは、import staticでassertEqualsを短く呼び出しています。Javaのテストクラスでは、静的インポートを使うことで検証行が読みやすくなる一方、どのライブラリのメソッドか分かりにくい場合はAssertions.assertEqualsと書く選択もあります。
Mockitoを使用したサンプルコード
Mockitoの応用例では、サービスクラスがリポジトリへ問い合わせる場面を想定すると整理できます。データベースへ接続せずに戻り値を固定できるため、単体テストの対象をサービスロジックへ絞れます。
結果: 期待されるテスト結果は、findUserNameById(1)がJohnを返すようにモック化され、UserServiceの戻り値もJohnとして比較されることです。
このサンプルコードでは、UserRepositoryの実装を使わず、mockで代替オブジェクトを作っています。単体テストの応用例としては分かりやすい一方、UserServiceやUserRepositoryの定義が別途必要になる点に注意します。
💡 Tips: MockitoではwhenとthenReturnで戻り値を固定できると理解できます。呼び出し回数まで確認したい場合はverify(userRepository).findUserNameById(1)のような検証を追加します。
同様に、継承やオーバーライドを含むJavaプログラムでは、どの実装が呼ばれているかがテスト結果へ影響します。オーバーライドの基礎はJavaでマスターするオーバーライドの解説記事で確認できると覚えるとよいでしょう。
まとめ
Javaと単体テストを学ぶときは、プログラムの基本構文、メソッドの入力と戻り値、JUnitの検証方法をつなげて理解すると進めやすくなります。初心者向けの段階では、複雑なフレームワーク設定よりも、小さなサンプルコードで期待値を確認することが土台になります。
その土台ができると、テストケース作成では正常系、境界値、異常系を分けて考えられますし、これが一つの目安です。単体テストの注意点として、過剰な共通化、外部依存への直接接続、実装詳細への依存を避けると、変更に強いテストへ近づきます。
カスタマイズ方法では、JUnitの依存関係、Mockitoによるモック、失敗時メッセージ、テストデータの固定が中心になります。応用例では、サービスとリポジトリの分離、例外の検証、条件の多いプログラムの整理が扱いやすい題材です。
これらを順に押さえることで、Javaの解説記事を読むだけでなく、自分のプログラムへ単体テストを追加する流れを作れますが、覚えておくと役立つでしょう。サンプルコードを写す段階から、期待値を自分で変えて確認する段階へ進むと、テストケース作成の理解が深まります。
関連記事
- Java List型完全ガイド!初心者でもマスターできる7つのステップ
- Javaアノテーションの12選!初心者から上級者まで徹底ガイド
- Javaでうるう年を判定!初心者でも分かる9ステップ解説
- Javaエスケープ処理の10ステップマスターガイド
- Javaでマスターする!オーバーライドのたった7つのステップ
※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。


