Mục lục
Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu cách sử dụng ArgumentCaptor trong mockito. Đây là một tính năng khá thú vị nhưng vì điều kiện sử dụng tính năng này không thường xuyên nên rất dễ quên.
Sử dụng ArgumentCaptor trong trường hợp nào?
ArgumentCaptor cho phép chúng ta theo dõi các tham số truyền vào một method. ính năng này đặc biệt hữu ích khi chúng ta không thế truy cập các tham số này từ bên ngoài nhưng vẫn muốn kiểm tra giá trị của chúng khi truyền vào method.
Giả sử chúng ta có EmailService class dùng để gửi email được triển khai như sau
public class EmailService { private DeliveryPlatform platform; public EmailService(DeliveryPlatform platform) { this.platform = platform; } public void send(String to, String subject, String body, boolean html) { Format format = Format.TEXT_ONLY; if (html) { format = Format.HTML; } Email email = new Email(to, subject, body, format); platform.send(email); } }
Setup unit-test
Để tìm hiểu cách sử dụng ArgumentCaptor trước tiên chúng ta cần setup unit-test tích hợp mockito
@ExtendWith(MockitoExtension.class) public class EmailServiveTest { @Mock private DeliveryPlatform platform; @InjectMocks private EmailService emailService; }
Kể từ phiên bản Junit 5 việc tích hợp mockito rất đơn giản, chúng ta chỉ cần sử dụng @ExtendWith kết hợp với MockitoExtension class do mockito phát triển.
Các bạn lưu ý rằng DeliveryPlatform là mock-object sẽ được inject vào EmailService object trong quá trình thực thi unit-test.
ArgumentCaptor object
Việc khởi tạo một ArgumentCaptor object giờ đây khá đơn giản, chúng ta cần sử dụng @Captor annotation chú thích lên object thuộc tính cần khởi tạo.
@Captor ArgumentCaptor<Email> emailCaptor;
Áp dụng ArgumentCaptor
ArgumentCaptor cho phép chúng ta theo dõi giá trị của các tham số truyền vào một method được chỉ định. Để làm được điều này chúng ta cần kết hợp với Mockito.verify().
Ví dụ trong EmailService của chúng ta, hàm DeliveryPlatform#send() nhận vào một tham số là Email object và không trả về bất cứ dữ liệu nào. Để kiểm thử bằng unit-test trong trường hợp, chúng ta sẽ dùng ArgumentCaptor để theo dõi giá trị của Email object được truyền vào và verify giá trị các thuộc tính của nó.
Để theo dõi giá trị của email object được truyền vào chúng ta làm như sau
Mockito.verify(platform).send(emailCaptor.capture());
Để truy xuất giá trị của Email object đã truyền vào trước đó chúng ta sử dụng
Email emailCaptorValue = emailCaptor.getValue();
Kiểm thử ArgumentCaptor value
Sau khi hàm DeliveryPlatform#send() được thực thi, giá trị của tham số truyền vào sẽ được ghi lại, chúng ta có thể thực hiện việc kiểm tra tính đúng đắn của dữ liệu như sau
@ExtendWith(MockitoExtension.class) public class EmailServiveTest { @Mock private DeliveryPlatform platform; @InjectMocks private EmailService emailService = new EmailService(); @Captor private ArgumentCaptor<Email> emailCaptor; @Test public void whenDoesSupportHtml_expectHTMLEmailFormat() { String to = "[email protected]"; String subject = "Using ArgumentCaptor"; String body = "Hey, let'use ArgumentCaptor"; emailService.send(to, subject, body, true); Mockito.verify(platform).send(emailCaptor.capture()); Email value = emailCaptor.getValue(); assertEquals(Format.HTML, value.getFormat()); assertEquals(body, value.getBody()); assertEquals(subject, value.getSubject()); assertEquals(to, value.getAddress()); } }
ArgumentCaptor trong Static method
Ví dụ EmailService của chúng ta có thêm một method như sau
public class EmailService { // more code public void requestToDeft() { String url = "https://shareprogramming.net/"; DeliveryPlatform.requestTo(url); } }
Hàm requestToDeft() sử dụng static method DeliveryPlatform#requestTo() mà không trả về kết quả. Mockito cho phép chúng ta mock cả những static method thông qua mockito-line.
Để theo dõi dữ liệu được truyền vào static method chúng ta có thể làm MockedStatic.verify() như sau
@ExtendWith(MockitoExtension.class) public class EmailServiveTest { @InjectMocks private EmailService emailService = new EmailService(); @Captor private ArgumentCaptor<String> urlCaptor; @Test public void mockStaticMethodWithArgumentCaptor() { try (MockedStatic<DeliveryPlatform> mockedStatic = Mockito.mockStatic(DeliveryPlatform.class)) { emailService.requestToDeft(); mockedStatic.verify(() -> { DeliveryPlatform.requestTo(urlCaptor.capture()); assertEquals("https://shareprogramming.net/", urlCaptor.getValue()); }); } } }
Tóm lược
Qua bài viết này chúng ta đã biết cách kiểm thử giá trị truyền các tham số truyền vào của các method thông qua ArgumentCaptor. Tính ngày rất hữu ích khi chúng ta muốn kiểm thử giá trị của các tham số đầu vào của một method.
Các bạn có thể tham khảo mã nguồn đầy đủ tại: argumentcaptor
Nguồn tham khảo