【问题标题】:@RunWith(MockitoJUnitRunner.class) vs MockitoAnnotations.initMocks(this)@RunWith(MockitoJUnitRunner.class) 与 MockitoAnnotations.initMocks(this)
【发布时间】:2012-05-29 20:34:46
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • @ExtendWith(MockitoExtension.class) 完美运行!

标签: java junit4 mockito


【解决方案1】:

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

框架使用的自动验证确实值得拥有。如果您犯了这些错误之一,它会为您提供更好的报告。

  • 您调用静态 when 方法,但未使用匹配的 thenReturnthenThrowthen 完成存根。 (下面代码中的错误 1)

  • 您在模拟上调用 verify,但忘记提供方法调用 您正在尝试验证。 (下面代码中的错误 2)

  • doReturndoThrow 或之后调用when 方法 doAnswer 并通过一个模拟,但忘记提供方法 你正在尝试存根。 (下面代码中的错误 3)

如果您没有验证框架使用情况,则在以下调用 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 开始,有更多选项可以准确控制报告的问题类型。

【讨论】:

  • 我绝对不能说它们是一样的。在一个测试用例中,junit runner 设置对我来说失败并且没有正确注入我的模拟,除非我进行 initMocks 设置
  • 我们使用的是 testng 6.8.8 + mockito 1.10.19,显然我们不能使用 MockitoJUnitRunner,但验证框架仍然有效!它的工作原理与@David Wallace 完全相同。有人可以解释吗?这是因为我们还有 @Before* 回调和 MockitoAnnotations.initMocks(this) 吗?
  • @yuranos87 听起来像是你应该问的一个新问题。当你这样做时不要忘记包含你的代码 - 如果你不显示代码,问“为什么这个代码做 XYZ”有点毫无意义。
  • 使用 TestRunner 解决方案远远优于 @Rule
  • @alexandroid 我最好的建议是你自己写答案,使用@ExtendWith。这不是我真正了解的事情。 Stack Overflow 的伟大之处在于,在这样的问题上,您可以得到多个正确答案。
【解决方案2】:

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

就是这样。这只是一个偏好问题。

【讨论】:

  • 除了 initMocks() 行之外,任何其他设置仍然需要 @Before 方法,对吧?
  • @OceanBlue:当然,如果您的 @Before 方法包含除 initMocks() 之外的任何内容,那么您必须在迁移到 runner 后保留它。
  • 大卫华莱士关于框架验证的回答完全回答了我的问题,所以我接受了这个问题,但是 +1 指出这个跑步者不能与另一个跑步者一起使用,比如 Spring 跑步者。谢谢!
  • 我正在使用 Spring Boot,我可以说SpringJUnit4ClassRunner 会自动为我初始化模拟。不过,我不知道普通的 Spring。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多