@RunWith(MockitoJUnitRunner.class)vs MockitoAnnotations.initMocks(this)


118

在编写新的jUnit4测试时,我想知道是使用@RunWith(MockitoJUnitRunner.class) 还是MockitoAnnotations.initMocks(this)

我创建了一个新测试,并且向导使用Runner自动生成了一个测试。MockitoJUnitRunner的Javadocs声明以下内容:

与JUnit 4.4和更高版本兼容,此运行器添加了以下行为:

初始化带有Mock注释的模拟,因此不需要显式使用MockitoAnnotations.initMocks(Object)。在每种测试方法之前都要初始化模拟。在每种测试方法之后验证框架使用情况。

我尚不清楚使用Runner是否比我过去使用过的initMocks()方法有任何优势。

任何想法或链接将不胜感激!

Answers:


147

MockitoJUnitRunner为您提供框架使用情况的自动验证,以及自动验证initMocks()

框架使用的自动验证实际上是值得的。如果您犯了这些错误之一,它可以为您提供更好的报告。

  • 您调用静态when方法,但不具有匹配完成磕碰thenReturnthenThrowthen(以下代码中的错误1)

  • 您调用verify了一个模拟,但是忘记提供您尝试验证的方法调用。(以下代码中的错误2)

  • when在或 之后调用该方法doReturn,并传递一个模拟,但是忘记提供您尝试存根的方法。 (以下代码中的错误3)doThrowdoAnswer

如果您没有验证框架使用情况,则在以下对Mockito方法的调用之前,不会报告这些错误。这可能是

  • 在相同的测试方法中(例如下面的错误1),
  • 在下一个测试方法中(例如下面的错误2),
  • 在下一堂课中。

如果它们在您运行的最后一个测试中发生(如下面的错误3),则根本不会报告它们。

这是每种错误类型的外观。此处假定JUnit按照此处列出的顺序运行这些测试。

@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. 
}

现在,当我五年多前第一次写这个答案时,我写了

因此,我建议MockitoJUnitRunner尽可能使用。但是,正如Tomasz Nurkiewicz正确指出的那样,如果需要另一个JUnit运行器(例如Spring),则不能使用它。

我的建议现在已更改。自从我第一次写这个答案以来,Mockito团队就增加了一个新功能。这是一个JUnit规则,其功能与完全相同MockitoJUnitRunner。但这更好,因为它不排除使用其他跑步者。

包括

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

在您的测试课中。这将初始化模拟,并使框架验证自动化;就像一样MockitoJUnitRunner。但是现在,您也可以使用SpringJUnit4ClassRunner或任何其他JUnitRunner。从Mockito 2.1.0开始,还有其他选项可精确控制要报告的问题类型。


我绝对不能说他们是一样的。在一个测试用例中,除非我进行了initMocks设置,否则junitRunner设置对我而言将失败,并且不会正确注入我的模拟
dtc

我们使用的是testng 6.8.8 +模拟的1.10.19,显然我们不能使用MockitoJUnitRunner,但是验证框架仍然有效!它与@David Wallace完全一样。有人可以解释吗?这是因为我们仍然有@ Before *回调和MockitoAnnotations.initMocks(this)吗?
yuranos '16

@ yuranos87听起来像是您应该提出的新问题。不要忘了在执行时包含您的代码-如果您不显示代码,则问“为什么此代码执行XYZ”有点毫无意义。
·伊本·卡里姆

1
使用TestRunner解决方案的效果远胜过@Rule
规则

1
@alexandroid我最好的建议是使用编写您自己的答案@ExtendWith。这不是我真正了解的东西。Stack Overflow的优点在于,在这样的问题上,您可以得到多个正确答案。
达伍德·本·卡里姆

24

使用runner可以节省一些编码(不需要@Before方法)。另一方面,有时无法使用跑步者,例如,当您已经在使用跑步者时SpringJUnit4ClassRunner

而已。这只是一个偏好问题。


2
除了initMocks()行之外,其他任何设置仍将需要@Before方法,对吗?
OceanBlue

2
@OceanBlue:当然,如果您的@Before方法包含任何内容,但initMocks()在迁移到运行程序之后必须保留它。
Tomasz Nurkiewicz 2012年

David Wallace关于框架验证的答案完全回答了我的问题,因此我接受了一个问题,但是+1指出该运行程序不能与其他运行程序一起使用,例如Spring。谢谢!
OceanBlue

1
我正在使用Spring Boot,可以说会SpringJUnit4ClassRunner自动为我初始化模拟。不过,我不了解纯春天。
gustavohenke '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.