Mockito: doAnswer Vs thenReturn


125

ฉันใช้ Mockito สำหรับการทดสอบหน่วยบริการในภายหลัง ฉันกำลังสับสนเมื่อจะใช้VSdoAnswerthenReturn

ใครสามารถช่วยฉันโดยละเอียด? จนถึงตอนนี้ฉันได้ลองใช้thenReturnแล้ว

คำตอบ:


167

คุณควรใช้thenReturnหรือdoReturnเมื่อคุณทราบค่าส่งคืนในเวลาที่คุณเยาะเย้ยการเรียกใช้เมธอด ค่าที่กำหนดนี้จะถูกส่งกลับเมื่อคุณเรียกใช้เมธอดจำลอง

thenReturn(T value) ตั้งค่าการส่งคืนที่จะส่งคืนเมื่อมีการเรียกใช้เมธอด

@Test
public void test_return() throws Exception {
    Dummy dummy = mock(Dummy.class);
    int returnValue = 5;

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenReturn(returnValue);
    doReturn(returnValue).when(dummy).stringLength("dummy");
}

Answer ถูกใช้เมื่อคุณต้องการดำเนินการเพิ่มเติมเมื่อมีการเรียกใช้เมธอดจำลองเช่นเมื่อคุณต้องการคำนวณค่าที่ส่งคืนตามพารามิเตอร์ของการเรียกใช้เมธอดนี้

ใช้เมื่อคุณต้องการต้นขั้ววิธีโมฆะกับทั่วไปdoAnswer()Answer

คำตอบระบุการดำเนินการที่ดำเนินการและค่าส่งคืนที่ส่งคืนเมื่อคุณโต้ตอบกับการจำลอง

@Test
public void test_answer() throws Exception {
    Dummy dummy = mock(Dummy.class);
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            String string = invocation.getArgumentAt(0, String.class);
            return string.length() * 2;
        }
    };

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenAnswer(answer);
    doAnswer(answer).when(dummy).stringLength("dummy");
}

สวัสดี @Roland Weisleder แต่บางครั้งคุณควรกลับค่าบางอย่างที่สร้างรหัสภายในและไม่มีอะไรจะทำอย่างไรกับข้อโต้แย้งเช่นผมพบว่าเป็นไปไม่ได้ในการดำเนินการนี้กับcode = UUID.randomUUID() mockito
zhuguowei

3
เมื่อจำลองของคุณควรกลับ UUID ใหม่สำหรับแต่ละภาวนาที่คุณจะใช้เพียงกับAnswer return UUID.randomUUID();
Roland Weisleder

ฉันสามารถใช้วิธีนี้จากมดการเริ่มต้นคำตอบใหม่ใส่ไว้ในวิธีการบางอย่างเพื่อทำให้โค้ดสะอาดขึ้นอีกนิดได้ไหม
สาย

3
@Line Answerเป็นอินเทอร์เฟซที่ใช้งานได้ดังนั้นด้วย Java 8 คุณสามารถแทนที่ด้วยนิพจน์แลมบ์ดา หากยังไม่สะอาดเพียงพอการปรับโครงสร้างอื่น ๆ ตามปกติและผิดปกติก็เป็นไปได้
Roland Weisleder

@ zhuguowei: ส่งคืนค่ารหัสภายในที่สร้างขึ้นหรือไม่? คุณหมายถึงอะไร?
Saurabh Patil

35

doAnswerและthenReturnทำสิ่งเดียวกันหาก:

  1. คุณกำลังใช้ Mock ไม่ใช่ Spy
  2. เมธอดที่คุณกำลังขีดฆ่ากำลังส่งคืนค่าไม่ใช่วิธีโมฆะ

มาล้อเลียน BookService นี้

public interface BookService {
    String getAuthor();
    void queryBookTitle(BookServiceCallback callback);
}

คุณสามารถต้นขั้ว getAuthor () โดยใช้และdoAnswerthenReturn

BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return "Joshua";
    }
}).when(service).getAuthor();

โปรดทราบว่าเมื่อใช้doAnswerคุณจะไม่สามารถส่งต่อวิธีการwhenได้

// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());

แล้วคุณจะใช้doAnswerแทนเมื่อthenReturnไหร่? ฉันนึกถึงการใช้งานสองกรณี:

  1. เมื่อคุณต้องการ "ต้นขั้ว" วิธีโมฆะ

การใช้ doAnswer คุณสามารถดำเนินการเพิ่มเติมบางอย่างเมื่อเรียกใช้เมธอด ตัวอย่างเช่นทริกเกอร์การเรียกกลับบน queryBookTitle

BookServiceCallback callback = new BookServiceCallback() {
    @Override
    public void onSuccess(String bookTitle) {
        assertEquals("Effective Java", bookTitle);
    }
};
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
        callback.onSuccess("Effective Java");
        // return null because queryBookTitle is void
        return null;
    }
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
  1. เมื่อคุณใช้ Spy แทน Mock

เมื่อใช้ when-thenReturn on Spy Mockito จะเรียกวิธีการจริงจากนั้นจะทำให้คำตอบของคุณสะดุด สิ่งนี้อาจทำให้เกิดปัญหาได้หากคุณไม่ต้องการเรียกใช้วิธีจริงเช่นในตัวอย่างนี้:

List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));

การใช้ doAnswer ทำให้เราสามารถตัดมันได้อย่างปลอดภัย

List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));

doReturnที่จริงถ้าคุณไม่ต้องการที่จะทำดำเนินการเพิ่มเติมเมื่อวิธีการอุทธรณ์คุณก็สามารถใช้

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));

จะเกิดอะไรขึ้นถ้าวิธีการเยาะเย้ยถือเป็นโมฆะ?
Igor Donin

1
อิกอร์นั่นคือสิ่งที่ doAnswer () เข้ามาในภาพและเขาได้กล่าวถึงในคำตอบด้านบน
Saurabh Patil

เมื่อใช้doAnswer(new Answer() { ... return null;}ฉันได้รับคำเตือนใน eclipse สำหรับ "คำตอบเป็นประเภทดิบการอ้างอิงถึงประเภททั่วไปคำตอบ <T> ควรกำหนดพารามิเตอร์" มีวิธีแก้ไขปัญหานี้หรือไม่ (ยกเว้นไม่สนใจคำเตือนของ c)
LazR
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.