Mockito - sự khác biệt giữa doReturn () và khi ()


196

Tôi hiện đang trong quá trình sử dụng Mockito để giả lập các đối tượng lớp dịch vụ của mình trong ứng dụng Spring MVC mà tôi muốn kiểm tra các phương thức Trình điều khiển của mình. Tuy nhiên, khi tôi đã đọc về các chi tiết cụ thể của Mockito, tôi đã thấy rằng các phương thức doReturn(...).when(...)này tương đương với when(...).thenReturn(...). Vì vậy, câu hỏi của tôi là điểm nào có hai phương thức làm cùng một việc hoặc sự khác biệt tinh tế giữa doReturn(...).when(...)và là when(...).thenReturn(...)gì?

Bất kỳ trợ giúp sẽ được đánh giá cao.


1
Javadoc có một vài trường hợp doReturn()hữu ích.
Sotirios Delimanolis

5
Tôi nghĩ một trong những khác biệt chính là doReturn (...). Khi (..) là loại cũ hơn và loại này không an toàn và do đó chúng tôi có thể sử dụng nó đôi khi khi trình biên dịch tiếp tục phàn nàn về việc truyền. Thời điểm (..). ThenReturn (..) tốt hơn nhiều về mặt an toàn loại
user2511882

Câu trả lời:


227

Hai cú pháp để khai thác là tương đương. Tuy nhiên, bạn luôn có thể sử dụng doReturn/whenđể khai thác; nhưng có những trường hợp bạn không thể sử dụng when/thenReturn. Phương pháp void stubbing là một trong những như vậy. Những người khác bao gồm sử dụng với các điệp viên Mockito, và khai thác cùng một phương pháp nhiều lần.

Một điều when/thenReturnmang lại cho bạn, điều doReturn/whenđó không, là kiểm tra kiểu giá trị mà bạn trả lại, tại thời điểm biên dịch. Tuy nhiên, tôi tin rằng điều này gần như không có giá trị - nếu bạn đã nhập sai loại, bạn sẽ tìm ra ngay khi bạn chạy thử nghiệm.

Tôi thực sự khuyên bạn chỉ nên sử dụng doReturn/when. Không có điểm nào trong việc học hai cú pháp khi một người sẽ làm.

Bạn có thể muốn tham khảo câu trả lời của tôi tại Forming Mockito "grammars" - một câu trả lời chi tiết hơn cho một câu hỏi liên quan rất chặt chẽ.


16
Tôi không đồng ý với David. Tôi thường gặp phải tình huống tôi trả lại loại sai khi sử dụng doReturn/whenvà dành vài phút tiếp theo để tìm ra điều gì sai. Kiểm tra kiểu biên dịch trở nên cực kỳ hữu ích với when/thenReturn.
Saket

11
Chỉ cần lưu ý rằng Mockito khuyên bạn nên sử dụng when/thenReturnthay vì doReturn/when.
CodyEngel

2
@CodyEngel và không có lý do gì cho một đề xuất như vậy, ngoài những gì tôi đã nêu trong câu trả lời của mình ở đây và tại stackoverflow.com/q/11462697 . Cách đây vài năm, tôi đã thảo luận điều này với Brice Dutheil, người hiện đang đóng vai trò là nhà phát triển chính của Mockito, và theo trí nhớ tốt nhất của tôi, anh ấy đồng ý. Tôi sẽ yêu cầu anh ấy đăng bình luận ở đây (không đảm bảo rằng anh ấy sẽ làm như vậy).
Dawood ibn Kareem

18
Các javadoc nói rằng đó doReturn/whenlà một sự đánh đổi. Nhóm không đề xuất cách này hay cách khác nhưng lưu ý when/thencách tiếp cận trực quan hơn, dễ đọc hơn và cung cấp kiểm tra thời gian biên dịch, đó là cách tiếp cận khiến Mockito trở nên phổ biến và dễ sử dụng, đừng quên rằng khi cơ sở mã được chia sẻ bởi kỹ năng khác nhau trong nhóm của bạn; nhưng nó có nhược điểm liên quan đến gián điệp và phương thức void.
Brice

5
Chỉ dành cho hồ sơ: doReturn()có nhược điểm lớn là chuyển sang mã hóa kiểu YODA của các cuộc gọi phương thức. Điều sau đó được viết ra đầu tiên đó là. Hầu hết mọi người đọc từ trái sang phải; vì vậy bây giờ bạn phải liên tục ghi nhớ để đảo ngược logic quay lại khi bạn nghĩ.
GhostCat

199

Cả hai cách tiếp cận đều hoạt động khác nhau nếu bạn sử dụng một đối tượng gián điệp (được chú thích bằng @Spy) thay vì giả (chú thích với @Mock):

  • when(...) thenReturn(...) thực hiện một cuộc gọi phương thức thực ngay trước khi giá trị được chỉ định sẽ được trả về. Vì vậy, nếu phương thức được gọi ném ngoại lệ, bạn phải xử lý / giả định nó, v.v ... Tất nhiên bạn vẫn nhận được kết quả của mình (những gì bạn xác định trong thenReturn(...))

  • doReturn(...) when(...) không gọi phương thức nào cả .

Thí dụ:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Kiểm tra:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");

37
Hành vi này chỉ hoạt động cho các đối tượng bị theo dõi, vì là "trình bao bọc" của các đối tượng thực. Trong trường hợp các đối tượng bị chế giễu, không thành vấn đề nếu đó là / thenReturn hoặc doReturn / when. Các đối tượng bị chế giễu không bao giờ gọi các phương thức thực.
Rafael Orágio

Bạn có thể vui lòng cung cấp thêm thông tin tại sao chúng ta cần sử dụng chức năng này? Tôi không thấy trường hợp sử dụng thực tế. Mục đích của kiểm tra là xác nhận tính chính xác của mã trong các trường hợp sử dụng khác nhau. Nếu calll của phương thức ném kiểm tra ngoại lệ sẽ ném ngoại lệ, không trả về giá trị
Gleichmut

@Gleichmut Đây là một tình huống giả định, trong đó tôi chỉ ra cách sử dụng / lợi thế của doReturn. Trong một ứng dụng thực tế, một phương thức chỉ trả về một ngoại lệ tất nhiên là vô nghĩa .. nhưng bạn có các phương thức (có thể không quá mỏng như phương pháp này) có thể ném ngoại lệ trong một số điều kiện nhất định ..
akcasoy

1
Chỉ để làm rõ: Phương thức when (). ThenReturn () - gọi phương thức thực tế (của một gián điệp - không quan trọng đối với giả) chỉ một lần. Điều này xảy ra trong dòng bạn chỉ định hành vi giả (khi ( myClass.anotherMethodInClass () .thenRet ...). Sau đó, phương thức thực tế không bao giờ được gọi lại. Có thể bạn nên biết nếu bạn đã mong đợi một số logic trang trí khi đọc giải thích ở trên.
Jonas

Đây dường như không phải là một lợi thế của doReturn()nó, nó trông giống như một sự lạm dụng của thư viện. Quan điểm của gián điệp thay vì chế giễu thuần túy là tận dụng các cuộc gọi thực sự. Họ cũng cảnh báo không sử dụng các gián điệp như thế này: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (và đề nghị mở rộng lớp học và ghi đè phương thức thay thế)
Matthew Đọc

13

Mockito javadoc dường như cho biết lý do tại sao sử dụng doReturn()thay vì when() sử dụng doReturn () trong những trường hợp hiếm hoi khi bạn không thể sử dụng Mockito.when (Object).

Xin lưu ý rằng Mockito.when (Object) luôn được khuyến nghị sử dụng vì nó là loại đối số an toàn và dễ đọc hơn (đặc biệt là khi ngắt các cuộc gọi liên tiếp).

Dưới đây là những dịp hiếm hoi khi doReturn () trở nên tiện dụng:

1. Khi gián điệp các đối tượng thực và gọi các phương thức thực trên một gián điệp mang lại tác dụng phụ

List list = new LinkedList(); List spy = spy(list);

// Không thể: phương thức thực được gọi là spy.get (0) ném IndexOutOfBoundException (danh sách vẫn trống)

when(spy.get(0)).thenReturn("foo");

// Bạn phải sử dụng doReturn () để khai thác: doReturn("foo").when(spy).get(0);

2. Ghi đè một ngoại lệ trước đó:

when(mock.foo()).thenThrow(new RuntimeException());

// Không thể: phương thức foo () stubbed ngoại lệ được gọi để RuntimeException được ném. when(mock.foo()).thenReturn("bar");

// Bạn phải sử dụng doReturn () để khai thác:

doReturn("bar").when(mock).foo(); Các kịch bản trên cho thấy một sự đánh đổi của cú pháp tao nhã của Mockito. Lưu ý rằng các kịch bản là rất hiếm, mặc dù. Hoạt động gián điệp nên lẻ tẻ và ghi đè ngoại lệ là rất hiếm. Không phải đề cập đến việc nói chung quá nhiều stubbing là một mùi mã tiềm năng chỉ ra quá nhiều stubbing.


6

Tiếp tục câu trả lời này , có một sự khác biệt khác là nếu bạn muốn phương thức của mình trả về các giá trị khác nhau, ví dụ như khi nó được gọi lần đầu, lần thứ hai được gọi, v.v. thì bạn có thể chuyển các giá trị, ví dụ như ...

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

Vì vậy, nó sẽ trả về false khi phương thức được gọi trong cùng một trường hợp thử nghiệm và sau đó nó sẽ trả về false một lần nữa và cuối cùng là true.


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.