junit-5-skill について
Java 開発者向けの JUnit 5 テストスキルです。一般的なテスト形式、Mockito の利用方法、本番向けのテストパターンを扱います。
主な機能
- 01単体テストと統合テストのガイド
- 02パラメーター化テストとネストテスト
- 03Mockito のテストパターン
- 04アサーションとライフサイクルの資料
- 05Maven と Gradle のテストコマンド
活用シーン
- 01Java の単体テスト作成
- 02Mockito を使ったサービスのテスト
- 03パラメーター化テストケースの作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ lambdatest/ agent-skills --skill junit-5-skillインストール後、Claude Code で/junit-5-skillを入力して読み込まれたか確認します。
同梱ファイルreference/advanced-patterns.mdreference/playbook.md
詳細
JUnit 5 テストスキル
あなたは、JUnit 5 テストを専門とするシニア Java 開発者です。
ステップ 1 — テストの種類
├─ "unit test", "assert" → Standard unit test
├─ "parameterized", "multiple inputs" → @ParameterizedTest
├─ "mock", "Mockito" → Unit test with Mockito
├─ "integration test", "Spring" → Read reference/spring-integration.md
└─ Default → Standard unit test
基本パターン
基本的なテスト
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
@DisplayName("Addition of two positive numbers")
void addPositiveNumbers() {
assertEquals(5, calculator.add(2, 3));
}
@Test
void divideByZero_throwsException() {
assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0));
}
@Test
void multipleAssertions() {
assertAll("calculator operations",
() -> assertEquals(4, calculator.add(2, 2)),
() -> assertEquals(0, calculator.subtract(2, 2)),
() -> assertEquals(6, calculator.multiply(2, 3))
);
}
}
アサーションのリファレンス
assertEquals(expected, actual);
assertNotEquals(unexpected, actual);
assertTrue(condition);
assertFalse(condition);
assertNull(object);
assertNotNull(object);
assertThrows(IllegalArgumentException.class, () -> service.process(null));
assertTimeout(Duration.ofSeconds(2), () -> service.longRunningOp());
assertAll("group",
() -> assertNotNull(user.getName()),
() -> assertTrue(user.getAge() > 0)
);
assertIterableEquals(List.of(1, 2, 3), actualList);
パラメーター化テスト
@ParameterizedTest
@ValueSource(strings = {"hello", "world", "junit"})
void stringIsNotEmpty(String value) {
assertFalse(value.isEmpty());
}
@ParameterizedTest
@CsvSource({"1,1,2", "2,3,5", "10,-5,5"})
void addNumbers(int a, int b, int expected) {
assertEquals(expected, calculator.add(a, b));
}
@ParameterizedTest
@MethodSource("provideUsers")
void validateUser(String name, int age, boolean expected) {
assertEquals(expected, validator.isValid(name, age));
}
static Stream<Arguments> provideUsers() {
return Stream.of(
Arguments.of("Alice", 25, true),
Arguments.of("", 25, false),
Arguments.of("Bob", -1, false)
);
}
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {" ", "\t"})
void blankStringsAreInvalid(String input) {
assertFalse(validator.isValid(input));
}
Mockito によるモック
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock private UserRepository userRepo;
@Mock private EmailService emailService;
@InjectMocks private UserService userService;
@Test
void createUser_savesAndSendsEmail() {
User user = new User("[email protected]", "Alice");
when(userRepo.save(any(User.class))).thenReturn(user);
User result = userService.createUser("[email protected]", "Alice");
assertNotNull(result);
verify(userRepo).save(any(User.class));
verify(emailService).sendWelcomeEmail("[email protected]");
}
@Test
void getUser_notFound_throwsException() {
when(userRepo.findById(99L)).thenReturn(Optional.empty());
assertThrows(UserNotFoundException.class, () -> userService.getUser(99L));
}
}
ネストされたテスト
@DisplayName("UserService")
class UserServiceTest {
@Nested
@DisplayName("when creating a user")
class CreateUser {
@Test void withValidData_succeeds() { }
@Test void withDuplicateEmail_throwsException() { }
}
@Nested
@DisplayName("when deleting a user")
class DeleteUser {
@Test void existingUser_removesFromDb() { }
@Test void nonExistentUser_throwsException() { }
}
}
アンチパターン
| 悪い例 | 良い例 | 理由 |
|---|---|---|
@Test public void test1() | @Test void shouldCalculateSum() | 説明的な名前 |
| プライベートメソッドをテストする | パブリック API 経由でテストする | 実装の詳細 |
| @DisplayName を付けない | 常に表示名を付ける | レポートが見やすくなる |
assertEquals(true, x) | assertTrue(x) | より読みやすい |
Maven の依存関係
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.14.0</version>
<scope>test</scope>
</dependency>
クイックリファレンス
| タスク | コマンド |
|---|---|
| すべて実行 | mvn test または ./gradlew test |
| クラスを実行 | mvn test -Dtest=UserServiceTest |
| メソッドを実行 | mvn test -Dtest=UserServiceTest#createUser_succeeds |
| タグ付きで実行 | @Tag("slow") + mvn test -Dgroups="slow" |
| 無効化 | @Disabled("Reason") |
| 条件付き | @EnabledOnOs(OS.LINUX) |
| タイムアウト | @Timeout(value = 5, unit = TimeUnit.SECONDS) |
| 繰り返し | @RepeatedTest(5) |
| 順序 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) |
応用パターン
本番環境向けのパターンについては、reference/playbook.md を参照してください。
| セクション | 内容 |
|---|---|
| §1 プロジェクトのセットアップ | Maven の依存関係、並列実行の設定、Surefire |
| §2 テストのライフサイクル | BeforeAll/Each、順序、タグ |
| §3 パラメーター化 | CsvSource、MethodSource、EnumSource、ValueSource |
| §4 Mockito | @Mock/@InjectMocks、キャプター、検証の順序 |
| §5 ネストされたテストと動的テスト | @Nested によるグループ化、@TestFactory |
| §6 AssertJ | 流れるようなアサーション、extracting、コレクションのチェック |
| §7 条件付き | @EnabledOnOs、assumptions、@EnabledIf |
| §8 カスタム拡張 | タイミング、再試行、BeforeTestExecution |
| §9 CI/CD | テストレポーターを使った GitHub Actions |
| §10 デバッグ表 | よくある 8 つの問題と解決策 |
| §11 ベストプラクティス | 本番環境向けチェックリスト 12 項目 |
コメント
Markdown 対応