1. test 1
  2. test 2
  3. test 3
  4. test 4
コース一覧
Spring Boot入門
Serviceの単体テスト

Spring Boot入門

Java で Web API サーバーを作るための Spring Boot の入門コースです。DI コンテナ、REST コントローラ、リクエスト検証、レイヤ分割、Spring Data JPA、例外ハンドリング、テストまでを扱います。毎レッスン、Spring が裏側でやっている判断そのものを pure Java の関数として自分で書き、フレームワークが何を肩代わりしてくれているのかを手触りで理解できる構成にしました。約 12 時間 (1 日 30 分 × 24 日) で 48 レッスンを修了できます。

1
Spring Bootとは何か
01. Spring Bootで何が作れるのか10分
02. サーブレットからフレームワークへ15分
03. ルーティング表という発想15分
04. プロジェクトの構成10分
05. 起動のしくみと自動設定15分
06. パスのマッチング15分
2
DIコンテナ
01. newで書くと何が困るのか15分
02. コンストラクタインジェクション15分
03. インターフェースへの依存15分
04. @Componentと@Bean15分
05. 自作のDIコンテナ20分
06. Beanのスコープとライフサイクル15分
3
RESTコントローラ
01. RESTという設計方針15分
02. @RestControllerの役割15分
03. @GetMappingとパス変数15分
04. クエリパラメータの受け取り15分
05. @PostMappingとリクエストボディ15分
06. ステータスコードの選び方15分
07. ResponseEntityで組み立てる15分
4
リクエストとレスポンスの変換
01. JSONとオブジェクトの往復15分
02. DTOとエンティティを分ける15分
03. recordでDTOを書く15分
04. 入力検証の基本15分
05. 検証エラーをまとめて返す15分
06. アノテーションによる検証15分
5
レイヤ構成とビジネスロジック
01. 3層アーキテクチャ10分
02. @Serviceに置くもの15分
03. 状態遷移をルールにする15分
04. 料金計算のような業務ロジック15分
05. @Transactionalとは何か15分
06. トランザクションの巻き戻し15分
6
データアクセス
01. @Entityとテーブルの対応15分
02. リポジトリという抽象15分
03. メソッド名からクエリを作る20分
04. 検索条件の組み立て15分
05. ページングと並び替え15分
06. N+1問題15分
7
例外処理と横断的関心事
01. 例外をHTTPに変換する15分
02. @ExceptionHandlerと@ControllerAdvice15分
03. エラーレスポンスの形を決める15分
04. フィルタとインターセプタ15分
05. ログとリクエストの追跡15分
06. 設定値の外部化15分
8
テストと仕上げ
01. テストの種類と使い分け15分
02. Serviceの単体テスト15分
03. モックで依存を差し替える15分
04. MockMvcでエンドポイントを試す15分
05. 本番へ出すための次の一歩10分

Serviceの単体テスト

このレッスンでは、Service の業務ロジックを Spring を起動せずに検証する書き方を身につけます。

Service の単体テストに Spring は要りません

前のレッスンで見たとおり、最も速いテストは Spring をまったく起動しないテストです。Service が持っている値引き計算や状態判定のようなロジックは、DI コンテナがあってもなくても同じ結果を返します。つまり確かめるのにコンテナは不要です。

Java

class PriceServiceTest { @Test void 千円以上は1割引になる() { PriceService service = new PriceService(); // ただの new assertEquals(900, service.discount(1000)); } }

テストクラスに @SpringBootTest は付いていません。@Autowired もありません。ただ new して呼ぶだけです。これで数百件書いても数秒で終わります。

依存があるときは偽物を渡します

Service が Repository を持っている場合はどうするか。ここで効いてくるのが、このコースの序盤で扱ったコンストラクタインジェクションです。依存をコンストラクタで受け取る設計にしておけば、テストからは好きなものを渡せます。

Java

@Service class UserService { private final UserRepository repository; UserService(UserRepository repository) { // ここが差し替え口になる this.repository = repository; } }

テストでは本物のデータベースにつながる UserRepository ではなく、決まった値を返すだけの偽物を渡します。データベースの用意も後片付けも不要になり、しかも「見つからなかったとき」のような再現しづらい状況を自由に作れます。フィールドインジェクションではこの差し替えができないので、コンストラクタインジェクションが推奨されるという話は、テストの側から見ると特にはっきりします。偽物の作り方そのものは次のレッスンで詳しく扱います。

JUnit 5 の基本

テストメソッドには @Test を付けます。判定には Assertions のメソッドを使います。よく使うものは次の通りです。

メソッド何を確かめるか
assertEquals(expected, actual)値が等しいこと
assertTrue(condition)条件が真であること
assertNull(value)null であること
assertThrows(型, 実行)指定した例外が投げられること

引数の順番は期待値が先、実際の値が後です。逆に書いても多くの場合テストは通ってしまいますが、失敗したときのメッセージが期待値と実測値を取り違えた形で出るので読み違えます。

AAA という組み立て方

テストメソッドの中身は、3つの段に分けて書くと読みやすくなります。準備、実行、検証の3段で、頭文字を取って AAA と呼びます。

Java

@Test void 会員は追加で5パーセント引かれる() { // 準備 (Arrange) PriceService service = new PriceService(); // 実行 (Act) int actual = service.discount(1000, true); // 検証 (Assert) assertEquals(850, actual); }

実行の行が1行だけになっていることが大事です。ここが何行にもなっているテストは、一度に複数のことを確かめようとしている合図です。失敗したときにどこが壊れたのか分からなくなるので、テストを分けます。

何を確かめるべきか

単体テストで狙うべきは分岐と境界です。値引きの例なら、1000円未満、ちょうど1000円、1000円を超える、といった境目を並べます。バグは条件の境目に住み着くので、真ん中の値だけを確かめても意味が薄いのです。

演習で書くこと

値引き計算という業務ロジックと、それを確かめる assertEquals に相当する判定を自分で書きます。そして複数の入力に対して期待値と一致したかどうかを pass と fail の並びとしてまとめて返します。JUnit が裏でやっている「呼んで、比べて、結果を記録する」という流れを、自分の手で組み立てることになります。

要件

  1. discount は価格が負なら -1 を返し、10000 以上で 20、1000 以上で 10、それ未満で 0 の割引率を使い、member が true ならその割引率に 5 を足すこと
  2. 値引き後の価格は price - price * rate / 100 で計算し、int の演算のままにすること
  3. runTests は 2 件分の判定結果を pass または fail としてカンマでつないだ文字列を返すこと

入出力例

runTests(1000, false, 900, 10000, false, 8000) → "pass,pass" runTests(500, false, 500, 1000, true, 850) → "pass,pass" runTests(-1, false, -1, 10000, true, 7500) → "pass,pass" runTests(1000, false, 999, 999, false, 999) → "fail,pass"

ヒント

割引率を int の変数 rate に決めてから、member が true のときだけ rate += 5 とすると分岐が重なりません

assertEquals は expected == actual を返すだけの短いメソッドで構いません

三項演算子を使うと、判定結果を pass と fail のどちらかの文字列に変えるところが1行で書けます

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/09

関連レッスン

  • モックで依存を差し替える

    呼び出し回数を記録する偽の実装を作れるようになります。

  • MockMvcでエンドポイントを試す

    リクエストの組み立てから期待する結果までを検証します。

  • 本番へ出すための次の一歩

    ビルド、プロファイル、セキュリティなど次に学ぶ範囲を見通します。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • テストバグを見つける工程
  • コンテナデータ取得や状態を担う上位コンポーネント
  • クラスデータと振る舞いを束ねる単位
  • コンストラクタインスタンス生成時の初期化処理
  • 設計何をどう作るかを決める前工程
  • データベースデータを構造化して保存する仕組み
  • フィールドクラスが持つデータ
  • メソッドクラスに属する関数
main.java
学習モード
エディタを読み込んでいます

メモ

Serviceの単体テスト

⌘S で保存