Javaの単体テストはどこまで書く?テストケースの考え方とカバレッジの目安

本記事は、Schooの「Java入門 中級【2026年版】」第3回「単体テストによるビジネスロジック検証」を学ぶ前後に、単体テストでどこまでテストケースを考えればよいかを整理したい方向けの記事です。
単体テストを学び始めると、「入力できる値を全部試す必要があるのか」「どの値を選べば十分なのか」で迷いやすくなります。結論から言うと、すべての値を試す必要はありません。ただし、仕様の分岐、境界値、異常値、重要な業務ルールは意識して選ぶ必要があります。
Schoo コースページ:Java入門 中級【2026年版】
テストケースは仕様文から作る
テストケースは、思いつきで値を並べるものではありません。まず仕様文を読み、条件と期待する結果を分けます。そのうえで、各条件を確認できる入力値を選びます。
たとえば、次の仕様からテストケースを作るとします。
購入金額が5000円以上なら送料は0円。5000円未満なら送料は500円。購入金額が0円未満の場合は例外とする。
手順1:仕様文を条件と期待結果に分ける
最初に見るのは、仕様文の中にある「なら」「場合」「以上」「未満」のような言葉です。これらは、プログラムの条件分岐やテストケースの候補になりやすい表現です。
ここで大事なのは、先にJUnitコードを書かないことです。まず「この条件なら、この結果になる」という対応を表にします。
手順2:テストケース仕様書の列を決める
実務でテストケースを整理する場合は、表にして残すことがあります。最初は難しい書式にする必要はありません。少なくとも、確認観点、前提・条件、入力値、期待結果、確認方法が分かれば、あとからJUnitコードに変換しやすくなります。
確認観点には、「5000円未満の送料」「5000円ちょうどの境界」「0円未満の入力」のように、何を確かめたいのかを書きます。入力値だけを書くと、なぜその値を選んだのかが分からなくなりやすいためです。
手順3:各条件から入力値を選ぶ
条件を分けたら、入力値を選びます。このとき、代表値、境界値、異常値に分けると、何を選べばよいかが具体的になります。
- 代表値:その条件に普通に入る値
- 境界値:条件が切り替わる直前、ちょうど、直後の値
- 異常値:仕様上、受け付けない値
送料計算なら、3000 や 10000 は代表値、4999 や 5000 は境界値、-1 は異常値として考えられます。
手順4:テストケース仕様書に記入する
入力値を選んだら、テストケース仕様書として1行ずつ整理します。ここでは「なぜその値を確認するのか」が分かるように、確認観点と前提・条件も書きます。
この表があると、レビューするときにも「5000円ちょうどの確認が抜けていないか」「異常値の確認があるか」を見つけやすくなります。
手順5:まず最低限のテストケースをそろえる
最初から完璧なテストケースを作ろうとすると迷います。まずは、次の3つがそろっているかを確認します。
- 正常に処理される代表値
- 条件が切り替わる境界値
- 仕様上受け付けない異常値
たとえば 3000、3001、3002 は、送料計算では同じ「5000円未満」のルートを通ります。もちろんまったく無意味ではありませんが、最初に増やすべき値ではありません。
それよりも、4999 と 5000 のように結果が切り替わる値を確認したほうが、条件式のミスを見つけやすくなります。
手順6:テストケース仕様書をJUnitコードにする
テストケース仕様書ができたら、表の1行をJUnitコードへ変換します。戻り値を確認する行は assertEquals、例外を確認する行は assertThrows にします。
assertEquals(500, calculator.calculateFee(4999));
assertEquals(0, calculator.calculateFee(5000));
assertEquals(0, calculator.calculateFee(5001));
このように境界の前後を確認すると、条件式を >= ではなく > と書いてしまった場合にも気づきやすくなります。
異常値の行は、戻り値を比べるのではなく、例外が通知されることを確認します。
assertThrows(
IllegalArgumentException.class,
() -> calculator.calculateFee(-1)
);
テストケース仕様書をもとにすると、テストコード全体は次のようになります。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class ShippingFeeCalculatorTest {
@Test
void testCalculateFee() {
ShippingFeeCalculator calculator = new ShippingFeeCalculator();
assertEquals(500, calculator.calculateFee(3000)); // TC-001
assertEquals(500, calculator.calculateFee(4999)); // TC-002
assertEquals(0, calculator.calculateFee(5000)); // TC-003
assertEquals(0, calculator.calculateFee(10000)); // TC-004
}
@Test
void testCalculateFeeThrowsExceptionWhenAmountIsNegative() {
ShippingFeeCalculator calculator = new ShippingFeeCalculator();
assertThrows(
IllegalArgumentException.class,
() -> calculator.calculateFee(-1) // TC-005
);
}
}
コメントの TC-001 から TC-005 は、テストケース仕様書の番号と対応しています。仕様書とテストコードを対応させると、どのテストケースがどのコードで確認されているかを追いやすくなります。
手順7:足りないテストと増やしすぎたテストを見分ける
テストケースが足りない状態とは、仕様の分岐や境界が確認できていない状態です。一方で、増やしすぎた状態とは、同じ意味の値ばかりを増やしている状態です。
まずは「各分岐を通る値があるか」「境界値を見ているか」「異常値を見ているか」を確認します。そのうえで、業務上ミスが大きな問題になる値があれば追加します。
カバレッジは目安であってゴールではない
カバレッジは、テストを実行したときに、プログラムのどの行や分岐が通ったかを示す目安です。カバレッジが高いことは大切ですが、それだけで十分とは限りません。
たとえば、5000円以上のルートと5000円未満のルートがどちらも通っていても、5000 ちょうどを試していなければ、境界の確認としては弱くなります。
カバレッジを見るときは、「行が通ったか」だけでなく、「その行をどの値で通したか」もセットで考えます。テストケース表に入力値と期待値を書いておくと、カバレッジの数字だけでは見えない確認漏れに気づきやすくなります。
どこまで書くかの目安
初学者のうちは、次の観点でテストケースを考えると、どこまで書くべきか判断しやすくなります。
すべての組み合わせを最初から試そうとする必要はありません。まずは、条件分岐、境界値、異常系、重要な業務ルールを押さえることを目標にします。
反対に、画面表示の文言、ログの細かい出力、あとから簡単に目視できるだけの処理などは、単体テストで細かく確認しすぎると、修正のたびにテストが壊れやすくなることがあります。単体テストでは、計算、判定、変換、例外など、プログラムの判断が入る部分を優先します。
つまり、テストケースの数ではなく、仕様上の大事な判断を確認できているかで考えることが大切です。
確認問題
次の仕様について、テストケース仕様書を作り、その内容をJUnitコードにしてみてください。
点数が80点以上ならA、60点以上80点未満ならB、60点未満ならC。点数が0未満または100を超える場合は例外とする。
確認観点、前提・条件、入力値、期待結果、確認方法を表に整理してから、JUnitコードに変換してみましょう。
演習後の確認:こちらのページを使って、自分で考えた内容を見直せます。
まとめ
- テストケースは、仕様文を条件と期待結果に分けて作る
- テストケース仕様書には、確認観点、前提・条件、入力値、期待結果、確認方法を書く
- 代表値、境界値、異常値を選ぶと、確認すべき値を決めやすい
- テストケース仕様書の1行を、
assertEqualsやassertThrowsに変換する - カバレッジは通った場所の目安であり、十分さそのものではない