@RunWith (MockitoJUnitRunner.class) so với MockitoAnnotations.initMocks (cái này)


118

Trong khi viết thử nghiệm jUnit4 mới, tôi đang phân vân nên sử dụng @RunWith (MockitoJUnitRunner.class) hay MockitoAnnotations.initMocks (this) .

Tôi đã tạo một bài kiểm tra mới và trình hướng dẫn tự động tạo một bài kiểm tra với Runner. Javadocs cho MockitoJUnitRunner nêu như sau:

Tương thích với JUnit 4.4 trở lên, trình chạy này bổ sung các hành vi sau:

Khởi tạo mocks được chú thích bằng Mock, do đó, việc sử dụng MockitoAnnotations.initMocks (Object) rõ ràng là không cần thiết. Mocks được khởi tạo trước mỗi phương pháp thử nghiệm. xác nhận việc sử dụng khung sau mỗi phương pháp thử nghiệm.

Tôi không rõ liệu việc sử dụng Runner có lợi thế nào so với phương thức initMocks () mà tôi đã sử dụng trước đây hay không.

Bất kỳ suy nghĩ hoặc liên kết sẽ được đánh giá cao!

Câu trả lời:


147

MockitoJUnitRunnercung cấp cho bạn xác nhận tự động việc sử dụng khuôn khổ, cũng như tự động initMocks().

Việc xác nhận tự động việc sử dụng khuôn khổ thực sự đáng có. Nó cung cấp cho bạn báo cáo tốt hơn nếu bạn mắc một trong những sai lầm này.

  • Bạn gọi tĩnh whenphương pháp, nhưng không hoàn thành stubbing với một khớp thenReturn, thenThrowhoặc then. (Lỗi 1 trong mã bên dưới)

  • Bạn gọi verifymột mô hình, nhưng quên cung cấp lệnh gọi phương thức mà bạn đang cố gắng xác minh. (Lỗi 2 trong mã bên dưới)

  • Bạn gọi whenphương pháp sau doReturn, doThrowhay doAnswervà vượt qua một mô hình, nhưng quên để cung cấp các phương pháp mà bạn đang cố gắng để còn sơ khai. (Lỗi 3 trong mã bên dưới)

Nếu bạn không có xác nhận của việc sử dụng khuôn khổ, những sai lầm không được báo cáo cho đến khi sau cuộc gọi đến một phương pháp Mockito. Đây có thể là

  • trong cùng một phương pháp kiểm tra (như lỗi 1 bên dưới),
  • trong phương pháp kiểm tra tiếp theo (như lỗi 2 bên dưới),
  • trong lớp kiểm tra tiếp theo.

Nếu chúng xảy ra trong bài kiểm tra cuối cùng mà bạn chạy (như lỗi 3 bên dưới), chúng sẽ không được báo cáo.

Đây là cách mỗi loại lỗi đó có thể trông như thế nào. Giả sử ở đây JUnit chạy các bài kiểm tra này theo thứ tự chúng được liệt kê ở đây.

@Test
public void test1() {

    // ERROR 1
    // This compiles and runs, but it's an invalid use of the framework because 
    // Mockito is still waiting to find out what it should do when myMethod is called.
    // But Mockito can't report it yet, because the call to thenReturn might 
    // be yet to happen.
    when(myMock.method1());

    doSomeTestingStuff();

    // ERROR 1 is reported on the following line, even though it's not the line with
    // the error.
    verify(myMock).method2();

}

@Test
public void test2() {

    doSomeTestingStuff();

    // ERROR 2
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call to verify.  But Mockito can't report 
    // it yet, because the call to the method that's being verified might 
    // be yet to happen.
    verify(myMock);
}

@Test
public void test3() {

    // ERROR 2 is reported on the following line, even though it's not even in 
    // the same test as the error.
    doReturn("Hello").when(myMock).method1();


    // ERROR 3
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call is being stubbed.  But Mockito can't 
    // report it yet, because the call to the method that's being stubbed might 
    // be yet to happen.

    doReturn("World").when(myMock);

    doSomeTestingStuff(); 

    //  ERROR 3 is never reported, because there are no more Mockito calls. 
}

Bây giờ khi tôi viết câu trả lời này lần đầu tiên hơn năm năm trước, tôi đã viết

Vì vậy, tôi muốn khuyên bạn nên sử dụng MockitoJUnitRunnerbất cứ nơi nào có thể. Tuy nhiên, như Tomasz Nurkiewicz đã chỉ ra một cách chính xác, bạn không thể sử dụng nó nếu bạn cần một JUnit runner khác, chẳng hạn như Spring.

Đề xuất của tôi bây giờ đã thay đổi. Nhóm Mockito đã thêm một tính năng mới kể từ lần đầu tiên tôi viết câu trả lời này. Đó là một quy tắc JUnit, thực hiện chính xác chức năng giống như MockitoJUnitRunner. Nhưng nó tốt hơn, bởi vì nó không loại trừ việc sử dụng các vận động viên khác.

Bao gồm

@Rule 
public MockitoRule rule = MockitoJUnit.rule();

trong lớp thử nghiệm của bạn. Thao tác này khởi tạo các mocks và tự động hóa xác thực khuôn khổ; giống như MockitoJUnitRunnerkhông. Nhưng bây giờ, bạn có thể sử dụng SpringJUnit4ClassRunnerhoặc bất kỳ JUnitRunner nào khác. Từ Mockito 2.1.0 trở đi, có các tùy chọn bổ sung kiểm soát chính xác loại sự cố được báo cáo.


tôi chắc chắn không thể nói chúng giống nhau. trong một trường hợp kiểm tra, thiết lập junit Á hậu không cho tôi và không tiêm mocks của tôi đúng, trừ khi tôi làm initMocks thiết lập
dtc

Chúng tôi đang sử dụng testng 6.8.8 + mockito 1.10.19 và rõ ràng là chúng tôi không thể sử dụng MockitoJUnitRunner, nhưng khung xác thực vẫn hoạt động! Và nó hoạt động chính xác như @David Wallace. Ai đó có thể giải thích? Điều này có phải do chúng ta vẫn còn gọi lại @ Before * và MockitoAnnotations.initMocks (cái này) không?
yuranos

@ yuranos87 Nghe có vẻ như bạn nên hỏi một câu hỏi mới. Đừng quên bao gồm mã của bạn khi bạn thực hiện - sẽ hơi vô nghĩa khi hỏi "tại sao mã này lại hoạt động XYZ" nếu bạn không hiển thị mã.
Dawood ibn Kareem

1
sử dụng giải pháp TestRunner hoạt động tốt hơn @Rule cho đến nay
Quy tắc

1
@alexandroid Đề xuất tốt nhất của tôi là bạn nên viết câu trả lời của riêng mình bằng cách sử dụng @ExtendWith. Đó không thực sự là điều tôi biết. Điều tuyệt vời về Stack Overflow là đối với một câu hỏi như thế này, bạn có thể đưa ra nhiều câu trả lời đúng.
Dawood ibn Kareem

24

Sử dụng Á hậu cho phép bạn tiết kiệm một chút mã hóa (không cần @Beforephương pháp). Mặt khác, việc sử dụng một con chạy đôi khi không thể thực hiện được, tức là khi bạn đã sử dụng một con chạy, như SpringJUnit4ClassRunner.

Đó là nó. Nó chỉ là một vấn đề của sở thích.


2
Ngoài dòng initMocks (), phương thức @Before vẫn cần thiết cho bất kỳ thiết lập nào khác, phải không?
OceanBlue

2
@OceanBlue: Tất nhiên nếu @Beforephương thức của bạn chứa bất kỳ thứ gì ngoại trừ việc initMocks()bạn phải bảo toàn nó sau khi chuyển sang Á hậu.
Tomasz Nurkiewicz

Câu trả lời của David Wallace về việc xác thực khung trả lời đầy đủ câu hỏi của tôi, vì vậy tôi đã chấp nhận câu trả lời đó, nhưng +1 vì chỉ ra rằng không thể sử dụng trình chạy này với một người chạy khác, như Spring. Cảm ơn!
OceanBlue

1
Tôi đang sử dụng Spring Boot và tôi có thể nói rằng điều đó SpringJUnit4ClassRunnersẽ tự động khởi tạo mocks cho tôi. Tuy nhiên, tôi không biết về mùa xuân đơn thuần.
gustavohenke
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.