Mô phỏng cuộc gọi đầu tiên không thành công, cuộc gọi thứ hai thành công


119

Tôi muốn sử dụng Mockito để kiểm tra mã (đơn giản hóa) bên dưới. Tôi không biết làm thế nào để nói Mockito thất bại lần đầu tiên, sau đó thành công lần thứ hai.

for(int i = 1; i < 3; i++) {
  String ret = myMock.doTheCall();

  if("Success".equals(ret)) {
    log.write("success");
  } else if ( i < 3 ) {
    log.write("failed, but I'll try again. attempt: " + i);
  } else {
    throw new FailedThreeTimesException();
  }
}

Tôi có thể thiết lập kiểm tra thành công với:

Mockito.when(myMock).doTheCall().thenReturn("Success");

Và thử nghiệm thất bại với:

Mockito.when(myMock).doTheCall().thenReturn("you failed");

Nhưng làm thế nào tôi có thể kiểm tra nếu nó thất bại một (hoặc hai lần) sau đó thành công, nó ổn?

Câu trả lời:


250

Từ các tài liệu :

Đôi khi chúng ta cần khai báo với giá trị trả về / ngoại lệ khác nhau cho cùng một cuộc gọi phương thức. Trường hợp sử dụng điển hình có thể là mô phỏng các trình lặp. Phiên bản gốc của Mockito không có tính năng này để thúc đẩy việc chế nhạo đơn giản. Ví dụ, thay vì các trình vòng lặp, người ta có thể sử dụng Lặp lại hoặc đơn giản là các bộ sưu tập. Chúng cung cấp những cách khai thác tự nhiên (ví dụ như sử dụng các bộ sưu tập thực). Tuy nhiên, trong một số trường hợp hiếm gặp, các cuộc gọi liên tiếp có thể hữu ích:

when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())
  .thenReturn("foo");

//First call: throws runtime exception:
mock.someMethod("some arg");

//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));

Vì vậy, trong trường hợp của bạn, bạn muốn:

when(myMock.doTheCall())
   .thenReturn("You failed")
   .thenReturn("Success");

25
Đây chỉ cho tôi đi đúng hướng (nhờ) cho kịch bản của tôi mà đã được xử lý bằng các phương pháp void - trong trường hợp đó bạn cần sử dụng các phong cách khác ...doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();
haggisandchips

38

Cách ngắn nhất để viết những gì bạn muốn là

when(myMock.doTheCall()).thenReturn("Success", "you failed");

Khi bạn cung cấp nhiều đối số thenReturnnhư thế này, mỗi đối số sẽ được sử dụng nhiều nhất một lần, ngoại trừ đối số cuối cùng, được sử dụng nhiều lần nếu cần. Ví dụ, trong trường hợp này, nếu bạn thực hiện cuộc gọi 4 lần, bạn sẽ nhận được "Thành công", "bạn thất bại", "bạn thất bại", "bạn thất bại".


22

Vì nhận xét liên quan đến vấn đề này khó đọc, tôi sẽ thêm một câu trả lời được định dạng.

Nếu bạn đang cố gắng thực hiện việc này với một voidhàm chỉ ném một ngoại lệ, theo sau là bước không có hành vi, thì bạn sẽ làm như sau:

Mockito.doThrow(new Exception("MESSAGE"))
            .doNothing()
            .when(mockService).method(eq());

4

Để thêm vào nàynày câu trả lời, bạn cũng có thể sử dụng một vòng lặp để chuỗi các cuộc gọi chế giễu. Điều này rất hữu ích nếu bạn cần chế nhạo cùng một thứ nhiều lần hoặc chế nhạo theo một số mẫu.

Ví dụ: (mặc dù một điều khác xa):

import org.mockito.stubbing.Stubber;

Stubber stubber = doThrow(new Exception("Exception!"));
for (int i=0; i<10; i++) {
    if (i%2 == 0) {
        stubber.doNothing();
    } else {
        stubber.doThrow(new Exception("Exception"));
    }
}
stubber.when(myMockObject).someMethod(anyString());

Tôi thực sự không biết về Stubber này và thấy nó hữu ích, +1.
Mihai Morcov

Đây sẽ là câu trả lời đúng nếu bạn cần gọi phương thức void.
db80

4

Tôi có một tình huống khác, tôi muốn giả lập một voidhàm cho cuộc gọi đầu tiên và chạy nó bình thường ở lần gọi thứ hai.

Điều này phù hợp với tôi:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
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.