Cách xác minh nhiều cuộc gọi phương thức với các tham số khác nhau


115

Tôi có phương pháp sau mà tôi muốn xác minh hành vi.

public void methodToTest(Exception e, ActionErrors errors) {
    ...

    errors.add("exception.message", 
            ActionMessageFactory.createErrorMessage(e.toString()));

    errors.add("exception.detail",
            ActionMessageFactory.createErrorMessage(e.getStackTrace()[0].toString()));

    ...
}

Trong lớp @Test của tôi, tôi đã hy vọng làm điều gì đó như thế này để xác minh rằng nó errors.add()được gọi bằng "exception.message" và một lần nữa với "exception.detail"

verify(errors).add(eq("exception.message"), any(ActionError.class));
verify(errors).add(eq("exception.detail"), any(ActionError.class));

tuy nhiên Mockito phàn nàn như sau

Argument(s) are different! Wanted:
actionErrors.add(
    "exception.message",
    <any>
);

Actual invocation has different arguments:
actionErrors.add(
    "exception.detail",
    org.apache.struts.action.ActionError@38063806
);

Làm cách nào để yêu cầu Mockito kiểm tra cả hai giá trị?


1
khi bạn có 2 phương thức với chữ ký khác nhau, bạn có thể viết trường hợp thử nghiệm riêng biệt cho cả hai.
Naveen Babu 14/12/11

8
Có, nhưng trong trường hợp này, nó có cùng một chữ ký phương thức nhưng chỉ khác các giá trị đối số
Brad

bạn có thể thử sử dụngMockito.reset()
takacsot

Câu trả lời:


102

Việc đọc thêm đã khiến tôi thử sử dụng ArgumentCaptors và các tác phẩm sau, mặc dù dài dòng hơn tôi muốn.

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);

verify(errors, atLeastOnce()).add(argument.capture(), any(ActionMessage.class));

List<String> values = argument.getAllValues();

assertTrue(values.contains("exception.message"));
assertTrue(values.contains("exception.detail"));

có cách nào để đảm bảo rằng các thông số nhất định đã được ghép nối bằng cách sử dụng phương pháp này không? Nói ví dụ như phương pháp của OP có hai đối số và muốn xác minh họ đã gọi nhau
committedandroider

1
Trường hợp thử nghiệm của OP gọi methodToTest()chính xác một lần, do đó, câu trả lời này xác minh rằng hai cuộc gọi được thực hiện cùng nhau. Giá trị được chụp List<String> valuesđang được xác nhận sẽ chỉ chứa hai giá trị đang được kiểm tra và không chứa các giá trị khác. Bạn cũng có thể thêm assertTrue(values.size == 2). Nếu đây là những gì bạn muốn tôi sẽ thay thế cho 3 câu assertTrue với một đơn hamcrest ...assertThat(values, contains("exception.message", "exception.detail"));
Brad

Trường hợp thử nghiệm của OP có gọi methodToTest () hai lần không?
committedandroider

xin lỗi tôi không rõ ràng. Tôi đang đề cập đến kịch bản OP muốn kiểm tra rằng hai đối số được gọi kết hợp. Vì vậy, chữ ký phương thức sẽ trông giống như public void methodToTest (Exception e, Message m, ActionErrors error) {để một ngoại lệ cụ thể được gọi với một thông báo cụ thể. Tôi cho rằng bạn chỉ có thể có hai ArgumentCaptors và sau đó lấy chỉ số và so sánh bằng cách sử dụng các giá trị vào những chỉ số trong cả hai danh sách các giá trị
committedandroider

Trường hợp thử nghiệm của OP gọi methodToTest()một lần. Đây là đối số phương thức ActionErrors errorsđược gọi nội bộ hai lần.
Brad

60

Nếu thứ tự của cả hai add()cuộc gọi có liên quan, bạn có thể sử dụng InOrder:

InOrder inOrder = inOrder(errors);
inOrder.verify(errors).add(eq("exception.message"), any(ActionError.class));
inOrder.verify(errors).add(eq("exception.detail"), any(ActionError.class));

7
Nó là đủ để vượt qua đơn errorslập luận: InOrder inOrder = inOrder(errors);(xem tài liệu )
GreenhouseVeg

2
Nếu đơn hàng KHÔNG liên quan thì sao? mà thường là trường hợp.
haelix

1
@haelix Trong trường hợp đó, hãy sử dụng câu trả lời Brads. Chuyển đổi Listthành Setvà khẳng định rằng Tập hợp các đầu vào bằng với tập hợp được đưa ra bởi các chụp đối số.
flopshot

25

Hãy thử một cái gì đó như sau:

verify(errors, times(2))
     .add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
          any(ActionError.class));

4
Kiểm tra của bạn rõ ràng là quá thoải mái.
haelix

17

bạn có thể có vấn đề trong mã của bạn. Bởi vì trên thực tế, bạn thực sự viết mã này:

Map<Character, String> map = mock(Map.class);

map.put('a', "a");
map.put('b', "b");
map.put('c', "c");

verify(map).put(eq('c'), anyString());
verify(map).put(eq('a'), anyString());
verify(map).put(eq('b'), anyString());

Lưu ý rằng xác minh đầu tiên thậm chí không theo thứ tự của các lời gọi thực tế.

Ngoài ra, tôi sẽ khuyên bạn thực sự không chế nhạo các loại mà bạn không sở hữu, ví dụ như loại thanh chống.

[CHỈNH SỬA @Brad]

Sau khi chạy mã Brice (ở trên) trong IDE của mình, tôi có thể thấy rằng tôi đã sử dụng ActionError thay vì ActionMessage, vì vậy đó là lý do tại sao xác minh () của tôi không khớp. Thông báo lỗi ban đầu tôi đăng đã khiến tôi hiểu nhầm rằng đó là đối số đầu tiên không khớp. Hóa ra đó là lập luận thứ hai.

Vì vậy, câu trả lời cho câu hỏi của tôi là

/** 
 * note that ActionMessageFactory.createErrorMessage() returns ActionMessage
 * and ActionError extends ActionMessage
 */
verify(errors).add(eq("exception.message"), any(ActionMessage.class));
verify(errors).add(eq("exception.detail"), any(ActionMessage.class));

1
Đừng hiểu những gì bạn đang cố gắng nói. Thứ tự xác minh có quan trọng không? nếu lệnh xác minh có vấn đề. Tại sao lại cung cấp api InOrder ở đây?
Oleksandr Papchenko

Cũng giống như những gì được viết ở trên, lệnh xác minh là không liên quan; đó là lý do tại sao có InOrder.
Brice

12

Bạn có thể sử dụng Mockito.atLeastOnce()để cho phép Mockito vượt qua bài kiểm tra ngay cả khi mockObject đó sẽ được gọi nhiều lần.

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));

1

1) Cho Mokito biết tổng số cuộc gọi mong đợi.

2) Cho Mokito biết số lần mỗi tổ hợp tham số được mong đợi.

verify(errors, times(2)).add(any(), any(ActionMessage.class));

verify(errors, atLeastOnce()).add(eq("exception.message"), any());
verify(errors, atLeastOnce()).add(eq("exception.detail"), any());

0

Theo cách tương tự với @ sendon1928, chúng ta có thể sử dụng:

Mockito.times(wantedInvocationCount)

để đảm bảo rằng phương pháp được gọi là số lần chính xác (giải pháp tốt hơn theo ý kiến ​​của tôi). Sau đó, chúng ta có thể gọi

Mockito.verifyNoMoreInteractions(mock)

Để đảm bảo rằng mô hình đó không được sử dụng thêm trong bất kỳ ngữ cảnh nào. Ví dụ đầy đủ:

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(2));

Mockito.verifyNoMoreInteractions(mockObject)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.