Mockito応用:ArgumentCaptorとスパイ
ArgumentCaptorでメソッド引数を取得し、Mockito.spyで実際のオブジェクトを部分的にモックします。
「Mockito応用:ArgumentCaptorとスパイ」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
ArgumentCaptor: メソッド引数のキャプチャ
ArgumentCaptor は、モックされたメソッドに渡された引数をキャプチャし、その内容を検証できるようにします。テスト対象の内部で引数が組み立てられ、直接アクセスできない場合に便利です。
ArgumentCaptor の作成と使用
引数の型に対応する captor を作成し、verify() の引数マッチャーとして captor.capture() を渡します。その後、captor.getValue() を呼び出してキャプチャした引数を取得します。
@Test
void sends_correct_email() {
ArgumentCaptor<EmailMessage> captor = ArgumentCaptor.forClass(EmailMessage.class);
userService.register(new CreateUserRequest("alice@example.com"));
verify(emailService).send(captor.capture());
EmailMessage msg = captor.getValue();
assertEquals("alice@example.com", msg.getTo());
assertTrue(msg.getSubject().contains("Welcome"));
}@Captor アノテーション
@ExtendWith(MockitoExtension.class) と @Captor を使用すると、冗長な ArgumentCaptor.forClass() の呼び出しを避けられます。
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock EmailService emailService;
@Captor ArgumentCaptor<EmailMessage> emailCaptor;
@Test
void captures_email() {
// ...
verify(emailService).send(emailCaptor.capture());
assertEquals("Welcome!", emailCaptor.getValue().getSubject());
}
}複数回の呼び出しをキャプチャする
メソッドが複数回呼び出される場合は captor.getAllValues() を使用します。呼び出し順に、キャプチャしたすべての値のリストを返します。
verify(emailService, times(3)).send(emailCaptor.capture());
List<EmailMessage> messages = emailCaptor.getAllValues();
assertEquals(3, messages.size());
assertEquals("Confirmation", messages.get(0).getSubject());Mockito のスパイ: 部分的なモック
Mockito.spy() は実際のオブジェクトをラップします。明示的にスタブ化しない限り、すべてのメソッドは通常どおり動作します。一部にテストしにくい依存関係があるものの、大部分はそのまま動作するクラスをテストする場合に使用します。
List<String> realList = new ArrayList<>();
List<String> spy = Mockito.spy(realList);
spy.add("hello"); // calls real ArrayList.add()
System.out.println(spy.size()); // 1 — real method called
doReturn(42).when(spy).size(); // stub just size()
System.out.println(spy.size()); // 42 — stubbed@Spy アノテーション
@ExtendWith(MockitoExtension.class) と @Spy を使用してスパイを作成します。フィールドはインライン、または @Spy UserService svc = new UserService(repo); のように初期化しておく必要があります。
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Spy
OrderService orderService = new OrderService(mockRepo, mockEmail);
}@SpyBean による Spring Bean のスパイ化
Spring Boot のテストでは、@SpyBean によって既存の Spring Bean を Mockito のスパイでラップできます。スタブ化しない限り実際の動作が行われます。@SpringBootTest と組み合わせて使用します。
@SpringBootTest
class IntegrationTest {
@SpyBean EmailService emailService;
@Test
void order_sends_email() {
orderService.placeOrder(cart);
verify(emailService).sendConfirmation(any());
}
}スパイでの doReturn と when().thenReturn() の違い
スパイでは、when(spy.method()).thenReturn(value) の代わりに doReturn(value).when(spy).method() を使用します。when(spy.method()) 形式では実際のメソッドが呼び出されるため、副作用が発生する可能性があります。
// Correct for spies:
doReturn(List.of()).when(spy).findAll();
// WRONG for spies — calls real findAll() first:
when(spy.findAll()).thenReturn(List.of()); // real method called!操作が行われていないことの検証
モックが一度も呼び出されていないことを検証するには verifyNoInteractions(mock) を使用します。期待されるすべての呼び出しの後に verifyNoMoreInteractions(mock) を使用すると、予期しない呼び出しを検出できます。
verifyNoInteractions(emailService); // never called
verify(repo).save(any());
verifyNoMoreInteractions(repo); // save() was the only interactionInOrder による検証
InOrder を使用すると、モックされたメソッドが特定の順序で呼び出されたことを検証できます。
InOrder inOrder = inOrder(repo, emailService);
inOrder.verify(repo).save(any());
inOrder.verify(emailService).send(any()); // save happened BEFORE send引数マッチャー
captor は any()、eq()、anyString()、argThat(predicate) などのマッチャーと組み合わせて使用できます。いずれかの引数でマッチャーを使用する場合は、すべての引数でマッチャーを使用する必要があります。
verify(repo).save(argThat(user ->
user.getEmail().endsWith("@example.com") &&
user.getStatus() == UserStatus.ACTIVE));クイックチェック
スパイをスタブ化するとき、when().thenReturn() ではなく doReturn を使用するのはなぜですか?
まとめ
ArgumentCaptor は、呼び出し後に検証できるよう引数をキャプチャします。スパイは実際のオブジェクトをラップし、スタブ化されていない限り処理を委譲します。スパイには doReturn を使用します。Spring の統合テストには @SpyBean を使用します。InOrder で呼び出し順序を検証します。
AI チューターと学ぶ Java — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 104
- レッスン
- 374
よくある質問
「Mockito応用:ArgumentCaptorとスパイ」レッスンは無料ですか?
はい。「Mockito応用:ArgumentCaptorとスパイ」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「Mockito応用:ArgumentCaptorとスパイ」で何を学びますか?
ArgumentCaptorでメソッド引数を取得し、Mockito.spyで実際のオブジェクトを部分的にモックします。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「Mockito応用:ArgumentCaptorとスパイ」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- @CsvSourceと@MethodSourceによるパラメータ化テスト
- Mockito応用:ArgumentCaptorとスパイ
- Spring Bootテストスライス:@WebMvcTestと@DataJpaTest
- Testcontainers:実データベースによる統合テスト