Mockito: doAnswer Vs thenReturn


124

Tôi đang sử dụng Mockito để thử nghiệm đơn vị dịch vụ sau này. Tôi bối rối khi sử dụng doAnswervs thenReturn.

Bất cứ ai có thể giúp tôi một cách chi tiết? Cho đến nay, tôi đã thử nó với thenReturn.

Câu trả lời:


167

Bạn nên sử dụng thenReturnhoặc doReturnkhi bạn biết giá trị trả về tại thời điểm bạn mô phỏng một cuộc gọi phương thức. Giá trị đã xác định này được trả về khi bạn gọi phương thức bị chế nhạo.

thenReturn(T value) Đặt một giá trị trả về sẽ được trả về khi phương thức được gọi.

@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 được sử dụng khi bạn cần thực hiện các hành động bổ sung khi một phương thức giả được gọi, ví dụ: khi bạn cần tính toán giá trị trả về dựa trên các tham số của lệnh gọi phương thức này.

Sử dụng doAnswer()khi bạn muốn khai báo một phương thức void với generic Answer.

Câu trả lời chỉ định một hành động được thực thi và một giá trị trả về được trả về khi bạn tương tác với mô hình.

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

chào @Roland Weisleder nhưng đôi khi bạn nên trả về một số mã bên trong được tạo giá trị và không liên quan gì đến các đối số, ví dụ: code = UUID.randomUUID()tôi thấy không thể thực hiện điều này với mockito.
zhuguowei

3
Khi mô hình của bạn sẽ trả về một UUID mới cho mỗi lời gọi, bạn sẽ triển khai Answerchỉ với return UUID.randomUUID();.
Roland Weisleder

Tôi có thể lấy phương thức này từ kiến ​​khởi tạo Trả lời mới đặt nó vào một phương thức nào đó, để làm cho mã sạch hơn một chút không?
Dòng

3
@Line Answerlà một giao diện chức năng, vì vậy với Java 8, bạn có thể thay thế nó bằng một biểu thức lambda. Nếu không đủ sạch sẽ có thể tái cấu trúc bất thường và bình thường khác.
Roland Weisleder

@ zhuguowei: trả về một số giá trị được tạo mã bên trong? Ý bạn là như thế nào?
Saurabh Patil,

34

doAnswerthenReturnlàm điều tương tự nếu:

  1. Bạn đang sử dụng Mock, không phải Spy
  2. Phương thức bạn đang khai thác đang trả về một giá trị, không phải là một phương thức void.

Hãy chế nhạo BookService này

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

Bạn có thể khai thác getAuthor () bằng cách sử dụng 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();

Lưu ý rằng khi sử dụng doAnswer, bạn không thể chuyển một phương thức vào when.

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

Vì vậy, khi nào bạn sẽ sử dụng doAnswerthay vì thenReturn? Tôi có thể nghĩ đến hai trường hợp sử dụng:

  1. Khi bạn muốn "khai" phương thức void.

Sử dụng doAnswer, bạn có thể thực hiện một số hành động bổ sung khi gọi phương thức. Ví dụ: kích hoạt một cuộc gọi lại trên 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. Khi bạn đang sử dụng Spy thay vì Mock

Khi sử dụng when-thenReturn trên Spy Mockito sẽ gọi phương thức thực và sau đó khai ra câu trả lời của bạn. Điều này có thể gây ra sự cố nếu bạn không muốn gọi phương thức thực, như trong mẫu này:

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

Sử dụng doAnswer chúng ta có thể khai thác nó một cách an toàn.

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

Trên thực tế, nếu bạn không muốn thực hiện các hành động bổ sung khi gọi phương thức, bạn có thể sử dụng doReturn.

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

điều gì sẽ xảy ra nếu phương thức chế nhạo là vô hiệu?
Igor Donin

1
Igor, đó chính xác là nơi doAnswer () xuất hiện và anh ấy đã đề cập đến điều đó trong câu trả lời ở trên.
Saurabh Patil,

Khi sử dụng, doAnswer(new Answer() { ... return null;}tôi nhận được cảnh báo trong eclipse cho "Câu trả lời là kiểu thô. Tham chiếu đến kiểu chung Câu trả lời <T> nên được tham số hóa". Có cách nào để giải quyết điều này (ngoại trừ việc bỏ qua cảnh báo của c) không?
LazR
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.