Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ
จับอาร์กิวเมนต์ของเมธอดด้วย ArgumentCaptor และจำลองออบเจ็กต์จริงบางส่วนด้วย Mockito.spy
Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
ArgumentCaptor: การดักจับอาร์กิวเมนต์ของเมธอด
ArgumentCaptor ดักจับอาร์กิวเมนต์ที่ส่งให้เมธอดจำลอง เพื่อให้คุณตรวจสอบอาร์กิวเมนต์เหล่านั้นได้ มีประโยชน์เมื่ออาร์กิวเมนต์ถูกสร้างขึ้นภายในระบบที่กำลังทดสอบและคุณไม่สามารถเข้าถึงได้โดยตรง
การสร้างและใช้ ArgumentCaptor
สร้างตัวดักจับสำหรับชนิดของอาร์กิวเมนต์ ส่ง captor.capture() เป็นตัวจับคู่อาร์กิวเมนต์ใน verify() จากนั้นเรียก 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
ใช้ @Captor ร่วมกับ @ExtendWith(MockitoExtension.class) เพื่อหลีกเลี่ยงการเรียก 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 Spies: การจำลองบางส่วน
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
ใช้ @Spy ร่วมกับ @ExtendWith(MockitoExtension.class) เพื่อสร้างสปาย ฟิลด์ต้องได้รับการเริ่มต้นค่า ไม่ว่าจะเริ่มต้นในบรรทัดเดียวกันหรือผ่าน @Spy UserService svc = new UserService(repo);
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Spy
OrderService orderService = new OrderService(mockRepo, mockEmail);
}การสอดส่อง Spring Bean ด้วย @SpyBean
ในการทดสอบ 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() สำหรับสปาย
สำหรับสปาย ให้ใช้ doReturn(value).when(spy).method() แทน when(spy.method()).thenReturn(value) รูปแบบ 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 interactionการตรวจสอบลำดับด้วย InOrder
ใช้ InOrder เพื่อยืนยันว่าเมธอดของออบเจ็กต์จำลองถูกเรียกตามลำดับที่กำหนด
InOrder inOrder = inOrder(repo, emailService);
inOrder.verify(repo).save(any());
inOrder.verify(emailService).send(any()); // save happened BEFORE sendตัวจับคู่อาร์กิวเมนต์
ใช้ตัวดักจับร่วมกับตัวจับคู่ ได้แก่ any(), eq(), anyString() และ argThat(predicate) หากอาร์กิวเมนต์ใดใช้อาร์กิวเมนต์ตัวจับคู่ อาร์กิวเมนต์ทั้งหมดต้องใช้ตัวจับคู่ด้วย
verify(repo).save(argThat(user ->
user.getEmail().endsWith("@example.com") &&
user.getStatus() == UserStatus.ACTIVE));ตรวจสอบอย่างรวดเร็ว
เหตุใดจึงควรใช้ doReturn แทน when().thenReturn() เมื่อตั้งค่าพฤติกรรมจำลองของสปาย
สรุป
ArgumentCaptor ดักจับอาร์กิวเมนต์เพื่อให้ตรวจสอบได้หลังการเรียกใช้ สปายจะห่อหุ้มออบเจ็กต์จริงและส่งต่อการทำงาน เว้นแต่จะกำหนดพฤติกรรมจำลองไว้ ใช้ doReturn กับสปาย ใช้ @SpyBean สำหรับการทดสอบการผสานรวมของ Spring ตรวจสอบลำดับการเรียกใช้ด้วย InOrder
คำถามที่พบบ่อย
บทเรียน “Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ”
จับอาร์กิวเมนต์ของเมธอดด้วย ArgumentCaptor และจำลองออบเจ็กต์จริงบางส่วนด้วย Mockito.spy คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การทดสอบแบบกำหนดพารามิเตอร์ด้วย @CsvSource และ @MethodSource
- Mockito ขั้นสูง: ตัวจับอาร์กิวเมนต์และสายลับ
- ส่วนทดสอบ Spring Boot: @WebMvcTest และ @DataJpaTest
- Testcontainers: การทดสอบการผสานรวมกับฐานข้อมูลจริง