จำลองการโทรครั้งแรกล้มเหลวการโทรครั้งที่สองสำเร็จ


119

ฉันต้องการใช้ Mockito เพื่อทดสอบโค้ด (ตัวย่อ) ด้านล่าง ไม่รู้จะบอกยังไงให้ Mockito ล้มเหลวในครั้งแรกแล้วทำครั้งที่สองให้สำเร็จ

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();
  }
}

ฉันสามารถตั้งค่าการทดสอบความสำเร็จด้วย:

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

และการทดสอบความล้มเหลวด้วย:

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

แต่ฉันจะทดสอบได้อย่างไรว่าถ้าล้มเหลวหนึ่งครั้ง (หรือสองครั้ง) แล้วประสบความสำเร็จก็ไม่เป็นไร

คำตอบ:


250

จากเอกสาร :

บางครั้งเราจำเป็นต้องขีดฆ่าด้วยค่าส่งคืน / ข้อยกเว้นที่แตกต่างกันสำหรับการเรียกใช้เมธอดเดียวกัน กรณีการใช้งานทั่วไปอาจเป็นการล้อเลียนตัวทำซ้ำ Mockito เวอร์ชันดั้งเดิมไม่มีคุณลักษณะนี้เพื่อส่งเสริมการล้อเลียนแบบธรรมดา ตัวอย่างเช่นแทนที่จะใช้ตัวทำซ้ำเราสามารถใช้ Iterable หรือเพียงแค่คอลเลกชัน สิ่งเหล่านี้นำเสนอวิธีการลอกลายแบบธรรมชาติ (เช่นการใช้คอลเลกชันจริง) ในสถานการณ์ที่เกิดขึ้นไม่บ่อยนักการหยุดการโทรติดต่อกันอาจมีประโยชน์แม้ว่า:

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"));

ดังนั้นในกรณีของคุณคุณต้องการ:

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

25
สิ่งนี้ชี้ให้ฉันไปในทิศทางที่ถูกต้อง (ขอบคุณ) สำหรับสถานการณ์ของฉันซึ่งจัดการกับวิธีการที่เป็นโมฆะ - ในกรณีนั้นคุณต้องใช้รูปแบบทางเลือก ...doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();
haggisandchips

38

วิธีที่สั้นที่สุดในการเขียนสิ่งที่คุณต้องการคือ

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

เมื่อคุณใส่อาร์กิวเมนต์หลายอาร์กิวเมนต์ให้เป็นthenReturnแบบนี้แต่ละอาร์กิวเมนต์จะถูกใช้ไม่เกินครั้งเดียวยกเว้นอาร์กิวเมนต์สุดท้ายซึ่งจะใช้กี่ครั้งก็ได้เท่าที่จำเป็น ตัวอย่างเช่นในกรณีนี้หากคุณโทร 4 ครั้งคุณจะได้รับ "สำเร็จ" "คุณล้มเหลว" "คุณล้มเหลว" "คุณล้มเหลว"


22

เนื่องจากความคิดเห็นที่เกี่ยวข้องกับเรื่องนี้อ่านยากฉันจะเพิ่มคำตอบที่จัดรูปแบบ

หากคุณกำลังพยายามทำสิ่งนี้ด้วยvoidฟังก์ชันที่เพิ่งแสดงข้อยกเว้นตามด้วยขั้นตอนที่ไม่มีพฤติกรรมคุณจะต้องทำสิ่งนี้:

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

4

เพิ่มในนี้และนี้คำตอบของคุณยังสามารถใช้ห่วงโซ่สายล้อเลียน สิ่งนี้มีประโยชน์หากคุณต้องล้อเลียนสิ่งเดียวกันหลาย ๆ ครั้งหรือล้อเลียนในบางรูปแบบ

เช่น (แม้ว่าจะเป็นคนที่ค้นพบได้ไกล):

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());

ที่จริงฉันไม่รู้เกี่ยวกับ Stubber นี้และพบว่ามีประโยชน์ +1
Mihai Morcov

นี่ควรเป็นคำตอบที่ถูกต้องหากคุณต้องการวิธีการโทรเป็นโมฆะ
db80

4

ฉันมีสถานการณ์ที่แตกต่างออกไปฉันต้องการจำลองvoidฟังก์ชันสำหรับการโทรครั้งแรกและเรียกใช้ตามปกติในการโทรครั้งที่สอง

สิ่งนี้ใช้ได้กับฉัน:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.