java-junit について
JUnit 5/6、AssertJ、Mockito を使った Java テストのガイダンスを提供するスキルです。既存の規約に従い、決定的なテストと安全なテスト運用を重視します。
主な機能
- 01既存のビルド・テスト規約の確認
- 02JUnit 5/6 のガイダンス
- 03アサーションと Mockito の実践
- 04決定的なテストの手法
- 05単体・統合テストの設定
- 06テストの安全性と検証ルール
活用シーン
- 01既存の Java プロジェクトへのテスト追加
- 02不安定なテストから時間や乱数依存を除去
- 03単体テストと統合テストの実行分離
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ github/ awesome-copilot --skill java-junitインストール後、Claude Code で/java-junitを入力して読み込まれたか確認します。
同梱ファイルreferences/assertj-and-mockito.mdreferences/build-setup.md
詳細
JUnit 5/6、AssertJ、Mockito による Java テスト
高速で決定的なユニットテストのための、フレームワークに依存しないガイダンスです。Spring のスライスには spring-boot-testing(インストールされている場合)を、Docker で実際のデータベースやブローカーを使う場合は java-testcontainers を使用してください。原因を説明できない失敗には java-debugging を使用してください。
まず、押し付けずに検出する
pom.xml/build.gradle*を読み、JUnit のバージョン(junit-jupiter、junit-bom、または Spring Boot BOM からの継承)、アサーションライブラリ、Mockito、Surefire/Failsafe のバージョン、Java のリリースを確認します。- 既存の
src/test/javaの規約(命名、アサーションライブラリ、static import、モックのスタイル)に合わせます。既存プロジェクトにない場合は、確認せずに AssertJ、Mockito、JaCoCo を導入しないでください。 - JUnit のメジャーバージョンを暗黙に上げないでください。アップグレードは独立したタスクです(インストールされている場合は
java-upgradeを参照してください)。
JUnit 5 と JUnit 6
| JUnit 5(最終版 5.14.x) | JUnit 6(6.0 リリース済み。現在のバージョンは 6.1.x) | |
|---|---|---|
| Java のベースライン | 8 | 17(公開済みの Gradle モジュールメタデータで確認済み) |
| バージョニング | Platform 1.x、Jupiter 5.x、Vintage 5.x | Platform、Jupiter、Vintage で共通のバージョン番号 |
| API | org.junit.jupiter.api.* | 同じパッケージです。このスキルの Jupiter テストは、5.14.4 と 6.0.3 のどちらでも変更なしでコンパイルおよび実行できます |
| 6.0 で削除 | MethodOrderer.Alphanumeric、非推奨の2引数版 InvocationInterceptor.interceptDynamicTest(Invocation, ExtensionContext) オーバーロード(3引数版は引き続き使用できます)、junit.jupiter.tempdir.scope、@CsvFileSource(lineSeparator) | |
| CSV | univocity-parsers | FastCSV:解析がより厳格になり(閉じ引用符の後に文字を置けません)、ヘッダーフィールドのオプションがヘッダーにも適用されるようになりました |
| その他 | junit-jupiter-migrationsupport は非推奨です。列挙型形式の設定値が無効な場合、ディスカバリーに失敗するようになりました。@Nested クラスの順序は決定的ですが、直感的ではありません |
出典:JUnit 6.0.0 のリリースノート(https://docs.junit.org/6.0.0/release-notes.html)。対象バージョンのリリースノート(https://docs.junit.org/current/release-notes/)を確認し、この表よりも優先してください。JUnit 4 のテストには Vintage エンジンが必要です。同じクラス内で org.junit.Test と org.junit.jupiter.api.Test を混在させないでください。
依存関係(5 と 6 で共通。Maven と Gradle で確認済み):org.junit:junit-bom をインポートし、test スコープで org.junit.jupiter:junit-jupiter(api、params、engine を集約)を宣言します。Gradle 9 ではさらに testRuntimeOnly("org.junit.platform:junit-platform-launcher") が必須です(確認済み:これがないとテスト実行エンジンは "Failed to load JUnit Platform" で失敗します)。また、tasks.test { useJUnitPlatform() } も必要です。Maven では Surefire 3.x が必要です(3.6.0 で確認済み)。
アサーション
プロジェクトで使われているライブラリに合わせます。Jupiter の基本ルールは、期待値を先に指定すること、遅延評価される Supplier メッセージ、assertAll、assertThrowsExactly、タイムアウトです。(別の instructions/java-junit5-assertions.instructions.md リソースには詳しい説明がありますが、このスキルにはインストールされません。)プロジェクトで AssertJ を使用している場合は、コレクション、文字列、例外には AssertJ を優先してください。パターン(ソフトアサーション、assertThatThrownBy、extracting、containsExactly、usingRecursiveComparison)は references/assertj-and-mockito.md にあります。
- 内部処理が何回呼び出されたかではなく、結果と状態をアサートします。
- 値を比較し、単独の
assertNotNullは避けてください。 - テストを通すために
AssertionError/Exceptionを決して捕捉しないでください。
モック化(Mockito)
- 境界をまたぐ協調オブジェクト(リポジトリ、HTTP クライアント、クロック、メッセージ送信機)をモック化します。値オブジェクト、レコード、コレクション、
String、テスト対象のクラスはモック化せず、実際のインスタンスまたは簡単なフェイクを使います。 - インタラクションが状態を持つ場合は、モックより手書きのフェイクを優先します。
@ExtendWith(MockitoExtension.class)と@Mock/@InjectMocks/@Captorを使います。ここでは厳格なスタブがデフォルトのため、未使用のスタブがあるとテストは失敗します(UnnecessaryStubbingException)。テストを修正してください。正当な理由がある共有セットアップに限り、@MockitoSettings(strictness = Strictness.LENIENT)で緩和します。- Mockito 5 では、デフォルトでインラインモックメーカーが使われます。JDK 21 以降では、自己アタッチして動的エージェントに関する警告が表示されることがあります。Mockito 5.14.0 以降では、代わりに
mockito-coreを-javaagentとして登録します(Maven と Gradle のセットアップはreferences/assertj-and-mockito.mdを参照。JDK 21 と 25 で検証済み)。まず解決済みのバージョンを確認してください。それ以前の 5.x の JAR にはPremain-Classがなく、エージェントとして使用できません。アップグレードする前に確認してください。それ以外の場合は、インストール済みのバージョン向けに文書化されている計測セットアップを使用します。 - Mockito 5 には Java 11 以降が必要です。デフォルトのインラインモックメーカーは GraalVM ネイティブイメージでは動作しません。その場合はサブクラスモックメーカーが適切です(Mockito 5.0.0 リリースノート、https://github.com/mockito/mockito/releases/tag/v5.0.0)。
mockStatic/mockConstructionは避け、静的呼び出しをインターフェースの背後にラップします。
決定性
- 時刻:
java.time.Clock(Clock.fixed(...))を注入してInstant.now(clock)を呼び出します。テスト対象のコードではInstant.now()/LocalDate.now()を避けます。 - 乱数:固定シードの
Random/RandomGeneratorを注入します。生成した場合はシードをログに記録します。 - デフォルトのロケール、タイムゾーン、ファイルエンコーディング、ネットワーク、実時間のスリープに依存しないでください。明示的に設定します(新しい 6.x リリースではロケール、タイムゾーン、システムプロパティ向けの組み込み拡張が追加されています。お使いのバージョンのリリースノートを確認し、それ以外の場合は try/finally を使用してください)。
ユニットテストと統合テスト
ユニット(*Test) | 統合(*IT) | |
|---|---|---|
| Maven | Surefire、mvn test | Failsafe、mvn verify |
| Gradle | test タスク | check に組み込まれた個別の integrationTest タスク(JVM Test Suite) |
| 速度 | ミリ秒単位、I/O なし | Docker/DB を使う場合があります |
Surefire のデフォルトでは *Test、Test*、*Tests、*TestCase が選ばれます。Failsafe では *IT、IT*、*ITCase が選ばれます。Failsafe には integration-test と verify のゴールをバインドする必要があり、mvn test ではなく mvn verify で実行します。代わりに @Tag で分けることもできます。データベースとブローカーについては java-testcontainers を、Spring のスライスについては spring-boot-testing を参照してください。ビルド設定の全例は references/build-setup.md を参照してください。
カバレッジとミューテーションテスト(任意)
- JaCoCo:プロジェクトで使用している場合、またはユーザーが求めた場合に限り追加します。Surefire/Failsafe では、JaCoCo エージェントが上書きされないように
<argLine>@{argLine} ...</argLine>を使います。 - カバレッジは問題を検出するための指標であり、目標ではありません。数値を上げるためにアサーションのないテストを追加しないでください。また、プロジェクトにないカバレッジゲートを追加しないでください。
- PIT(ミューテーションテスト)は時間がかかります。プロジェクトですでに使用している場合、またはユーザーが求めた場合に限り、変更したクラスのみを対象に実行します(検証済みの pitest-maven と JUnit 5 プラグインの実行記録がある
references/build-setup.mdを参照してください)。
エージェントのガードレール
- テストを成功させるために、失敗するテストを削除したり、コメントアウトしたり、
@Disabledを付けたり、弱めたり(アサーションを緩くする、許容範囲を広げる、例外を握りつぶすなど)、スキップしたりしてはいけません。原因を特定してください。 - テストと本番コードのどちらが誤っているか判断してください。修正によって本番環境での動作が変わる場合は、いったん作業を止めて、先にユーザーに確認してください。テストに明らかに古い期待値が記述されている場合は、その旨を伝え、変更案を提示してください。
- ビルドを成功させるために、
-DskipTests、-Dmaven.test.skip、-x test、failIfNoTests=falseを追加してはいけません。 - 正しさを「証明」するために、テスト対象のクラスをモックしたり、モックの内部状態をアサートしたりしてはいけません。
- まず対象を絞ったテストを実行し、その後、ビルド全体を実行してください。
- Maven:
mvn -q -Dtest=OrdersTest test(メソッドを1つ指定する場合:-Dtest='OrdersTest#place_should_saveAndNotify_when_itemValid')、次にmvn verify。 - Gradle:
./gradlew test --tests 'demo.OrdersTest'、次に./gradlew check。 プロジェクトラッパー(./mvnw、./gradlew)がある場合は、そちらを優先してください。
- Maven:
- 不安定なテストの場合は、再実行して再現させてから、非決定性の原因(時刻、実行順序、共有状態、非同期処理の待機)を取り除いてください。リトライを追加してはいけません。
- 新しいコードには、既存のテストと同じスタイルで、既存のテストの隣に新しいテストを追加してください。正常系、境界条件、エラーケースを網羅してください。
参考資料
references/assertj-and-mockito.md:AssertJ のパターン、Mockito の厳格性/キャプター/エージェントの設定、モックを避けるべき場合。references/build-setup.md:JUnit 5/6、Failsafe の分割、JaCoCo、PIT に対応した Maven および Gradle(Kotlin DSL)の設定。