ArgumentCaptor trong Mockito được dùng để bắt (capture) các tham số được truyền vào những phương thức mock. ArgumentCaptor thường được sử dụng cùng với phương thức Mockito.verify() để lấy ra các tham số đã được truyền vào khi một phương thức nào đó được gọi. Nhờ đó, chúng ta có thể viết thêm các JUnit assertions để kiểm tra kỹ hơn trong test.

Mockito ArgumentCaptor
Chúng ta có thể tạo một instance ArgumentCaptor cho bất kỳ class nào, sau đó method capture() sẽ được dùng kết hợp với verify(). Cuối cùng, chúng ta có thể lấy các arguments đã được capture bằng các method getValue() và getAllValues().
Method getValue() được dùng khi chỉ capture một argument. Nếu verified method được gọi nhiều lần thì getValue() sẽ trả về giá trị mới nhất được capture. Nếu có nhiều arguments được capture, hãy dùng getAllValues() để lấy danh sách các arguments đó.
Ví dụ về Mockito ArgumentCaptor
Giả sử chúng ta có một class được định nghĩa như sau:
class MathUtils {
public int add(int x, int y) {
return x + y;
}
public boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch (NumberFormatException e) {
return false;
}
return true;
}
public long squareLong(long l) {
return l*l;
}
}
Chúng ta có thể viết test case và sử dụng ArgumentCaptor như minh họa dưới đây.
@Test
void test() {
MathUtils mockMathUtils = mock(MathUtils.class);
when(mockMathUtils.add(1, 1)).thenReturn(2);
when(mockMathUtils.isInteger(anyString())).thenReturn(true);
ArgumentCaptor acInteger = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor acString = ArgumentCaptor.forClass(String.class);
assertEquals(2, mockMathUtils.add(1, 1));
assertTrue(mockMathUtils.isInteger("1"));
assertTrue(mockMathUtils.isInteger("999"));
verify(mockMathUtils).add(acInteger.capture(), acInteger.capture());
List allValues = acInteger.getAllValues();
assertEquals(List.of(1, 1), allValues);
verify(mockMathUtils, times(2)).isInteger(acString.capture());
List allStringValues = acString.getAllValues();
assertEquals(List.of("1", "999"), allStringValues);
}
Mockito @Captor
Chúng ta có thể sử dụng annotation @Captor để tạo argument captor ngay tại cấp độ field. Như vậy, thay vì phải khởi tạo ArgumentCaptor ở cấp độ field như sau:
ArgumentCaptor acLong = ArgumentCaptor.forClass(Long.class);
Chúng ta có thể sử dụng @Captor như sau:
@Captor ArgumentCaptor acLong;
Lưu ý rằng chúng ta phải gọi MockitoAnnotations.initMocks(this); trước các test methods để Mockito framework khởi tạo nó.
Ví dụ về Mockito @Captor
Dưới đây là một ví dụ đơn giản về annotation @Captor.
class MockitoArgumentCaptorExamples {
@Captor ArgumentCaptor acLong;
@Test
void test() {
MathUtils mockMathUtils = mock(MathUtils.class);
when(mockMathUtils.squareLong(2L)).thenReturn(4L);
assertEquals(4L, mockMathUtils.squareLong(2L));
verify(mockMathUtils).squareLong(acLong.capture());
assertTrue(2 == acLong.getValue());
}
}
Bạn có thể xem toàn bộ code và nhiều ví dụ khác về Mockito trong GitHub Repository của chúng tôi.