2011-11-11 27 views
153

Có cách nào để có phương thức gốc được trả về các đối tượng khác nhau trên lời gọi tiếp theo không? Tôi muốn làm điều này để kiểm tra các câu trả lời không xác định từ một số ExecutorCompletionService. tức là để kiểm tra không phân biệt thứ tự trả về của các phương thức, kết quả vẫn không thay đổi.Sử dụng Mockito với nhiều cuộc gọi đến cùng một phương thức với cùng một đối số

Mã tôi đang tìm kiếm để kiểm tra trông giống như thế này.

// Create an completion service so we can group these tasks together 
ExecutorCompletionService<T> completionService = 
     new ExecutorCompletionService<T>(service); 

// Add all these tasks to the completion service 
for (Callable<T> t : ts) 
    completionService.submit(request); 

// As an when each call finished, add it to the response set. 
for (int i = 0; i < calls.size(); i ++) { 
    try { 
     T t = completionService.take().get(); 
     // do some stuff that I want to test 
    } catch (...) { }   
} 

Trả lời

140

Bạn có thể làm điều đó bằng cách sử dụng thenAnswer phương pháp (khi chaining với when):

when(someMock.someMethod()).thenAnswer(new Answer() { 
    private int count = 0; 

    public Object answer(InvocationOnMock invocation) { 
     if (count++ == 1) 
      return 1; 

     return 2; 
    } 
}); 

Hoặc sử dụng tương đương, tĩnh doAnswer phương pháp:

doAnswer(new Answer() { 
    private int count = 0; 

    public Object answer(InvocationOnMock invocation) { 
     if (count++ == 1) 
      return 1; 

     return 2; 
    } 
}).when(someMock).someMethod(); 
+0

oooh, gọn gàng. các tài liệu nói về câu trả lời như là chỉ cho void, nhưng điều này là tuyệt vời! – Emma

+1

Điều đó thực sự giúp ích rất nhiều khi đưa ra các phương thức void cần phải cung cấp câu trả lời cho callbacks, trong đó không thể sử dụng 'thenReturn (val1, val2, ...) 'đơn giản hơn. Cảm ơn nhiều! –

+1

Là một tùy chọn khác cho câu trả lời ở trên, bạn cũng có thể kết hợp các phương thức doAnswer với nhau. Vì vậy, khi (someMock.someMethod()) doAnswer (new Answer1()). DoAnswer (new Answer2()); ' –

400

Làm thế nào về

when(method-call).thenReturn(value1, value2, value3); 

Bạn có thể đặt bao nhiêu đối số theo ý muốn trong các dấu ngoặc vuông rồiQuay lại, miễn là chúng đều là loại chính xác. Giá trị đầu tiên sẽ được trả về lần đầu tiên phương thức được gọi, sau đó là câu trả lời thứ hai, v.v. Giá trị cuối cùng sẽ được trả về nhiều lần khi tất cả các giá trị khác được sử dụng hết.

+2

Thao tác này sẽ hoạt động với mô hình, nhưng không phải với gián điệp. Nếu bạn cần phải ngăn chặn gọi phương thức ban đầu bạn cần doAnswer (...). When (someSpy) .someMethod (...). – Yuri

+1

@Yuri - không hoàn toàn. Bạn không cần 'doAnswer' hoặc viết' Trả lời' trong trường hợp bạn đề cập đến. Bạn chỉ có thể sử dụng 'doReturn (...). When (someSpy) .someMethod (...)'. Có vẻ hợp lý khi cho rằng Emma quan tâm đến mocks, chứ không phải là gián điệp, nhưng tôi đoán tôi có thể thêm một cái gì đó vào câu trả lời của tôi để đánh vần điều này. Cảm ơn bạn đã bình luận. –

+0

@DawoodibnKareem cho phép nói cho cuộc gọi đầu tiên tôi muốn trả về một giá trị và cho cuộc gọi thứ hai, tôi muốn ném một Ngoại lệ. Điều này có thể giải quyết như thế nào? – Rito

50

Bạn thậm chí có chuỗi doReturn() phương pháp invocations như thế này

doReturn(null).doReturn(anotherInstance).when(mock).method(); 

dễ thương phải không :)

54

Như previously pointed out gần như tất cả các cuộc gọi được thể kết nối.

Vì vậy, bạn có thể gọi

when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test")); 

//OR if you're mocking a void method and/or using spy instead of mock 

doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method(); 

Thông tin thêm trong Mockito's Documenation.

+2

Rất hữu ích! Điều gì sẽ xảy ra lần thứ 4 'mock.method' được gọi trong ví dụ này? Tôi muốn một cái gì đó như thế, trở lại foo lần đầu tiên nhưng trở lại thanh cho TẤT CẢ phần còn lại. – javaPlease42

+3

Mỗi lời gọi bổ sung trên mô hình sẽ trả về 'thenReturn' cuối cùng hoặc 'thenThrow' cuối cùng Rất hữu ích –

0

Sau đây có thể được sử dụng như một phương pháp phổ biến để trả về các đối số khác nhau về các cuộc gọi phương thức khác nhau. Điều duy nhất chúng ta cần làm là chúng ta cần truyền một mảng với thứ tự các đối tượng cần được lấy ra trong mỗi cuộc gọi.

@SafeVarargs 
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) { 
    return new Answer<Mock>() { 
     private int count=0, size=mockArr.length; 
     public Mock answer(InvocationOnMock invocation) throws throwable { 
      Mock mock = null; 
      for(; count<size && mock==null; count++){ 
       mock = mockArr[count]; 
      } 

      return mock;  
     } 
    } 
} 

Ví dụ: getAnswerForSubsequentCalls(mock1, mock3, mock2); sẽ trả về đối tượng mock1 trên cuộc gọi đầu tiên, đối tượng mock3 trên cuộc gọi thứ hai và đối tượng mock2 trên cuộc gọi thứ ba. nên được sử dụng như when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2)); này là gần như tương tự như when(something()).thenReturn(mock1, mock3, mock2);

4

Tôi đã thực hiện một lớp MultipleAnswer giúp tôi để còn sơ khai câu trả lời khác nhau trong mỗi cuộc gọi. Đây là đoạn mã:

private final class MultipleAnswer<T> implements Answer<T> { 

    private final ArrayList<Answer<T>> mAnswers; 

    MultipleAnswer(Answer<T>... answer) { 
     mAnswers = new ArrayList<>(); 
     mAnswers.addAll(Arrays.asList(answer)); 
    } 

    @Override 
    public T answer(InvocationOnMock invocation) throws Throwable { 
     return mAnswers.remove(0).answer(invocation); 
    } 
} 
Các vấn đề liên quan