为什么我们在junit测试中使用Mockitojunitrunner类?

Roh*_*rma 2 java junit mockito

我是mockito框架的新手,我对此有一个非常基本的问题,为什么我们在junit测试类中使用MockitoJunitRunner类.此外,我发现以下两点与此相关,但无法得到它,任何人都可以详细解释以下两点

框架使用的自动验证实际上值得拥有.如果您犯下其中一个错误,它会为您提供更好的报告.

  • 您在模拟上调用verify,但忘记提供您要验证的方法调用.
  • 你调用when方法之一(静态方法,或doReturn之后的方法,doThrow或doAnswer)并传递模拟,但忘记提供你试图存根的方法.

dav*_*xxx 6

使用MockitoJunitRunner而不是JunitRunner真正可选.

框架使用的自动验证实际上值得拥有.如果您犯下其中一个错误,它会为您提供更好的报告.

当您使用创建模拟的方式时,提供的主要优点MockitoJunitRunner是使您可以显式调用.MockitoAnnotations.initMocks(Object)@Mock

但是你也可以通过使用这个可能在不使用它的情况下丢失的跑步者获得更多关于Mockito框架的滥用报告.

Mockito 1.10.19版本的javadoc 说明:

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

  • 初始化用Mock注释的模拟,因此MockitoAnnotations.initMocks(Object)不需要显式使用 .在每种测试方法之前初始化模拟.

  • 验证每个测试方法后的框架使用情况.请参阅Mockito.validateMockitoUsage()的javadoc.

而最重要的部分:

Runner是完全可选的 - 还有其他方法可以让@Mock工作,例如通过编写基类.明确验证框架使用情况也是可选的,因为每次使用框架时Mockito都会自动触发它.请参阅javadoc Mockito.validateMockitoUsage().

在不使用以下情况下可能无法使用的错误使用示例MockitoJunitRunner:

 //Oops, thenReturn() part is missing:
 when(mock.get());

 //Oops, verified method call is inside verify() where it should be on the outside:
 verify(mock.execute());

 //Oops, missing method to verify:
 verify(mock);
Run Code Online (Sandbox Code Playgroud)

但是在所有情况下都无法捕捉到这些.

Mockito.validateMockitoUsage()由跑步者和框架本身调用的方法给出了更多关于它的解释,但实际上它并不完整.

validateMockitoUsage()显式验证框架状态以检测Mockito的无效使用.但是,此功能是可选的,因为Mockito始终验证使用情况...... 但是有一个问题,请继续阅读.

好.继续.

如果您滥用它,Mockito会抛出异常,以便您知道您的测试是否正确编写.问题是Mockito 下次使用框架时会进行验证(例如,下次验证时,存根,调用模拟等).但即使可能在下一个测试中抛出异常,异常消息也包含一个带有缺陷位置的可导航堆栈跟踪元素.因此,您可以点击并找到Mockito被滥用的地方.

因此,框架在您下次使用框架时进行验证(验证,存根,调用模拟等等).
事实上,这是真的,但并非总是如此.

例如,这个滥用将被框架捕获:

@Test
public void testBadUseWhen() throws Exception {
   Address mock = Mockito.mock(Address.class);
   Mockito.verify(mock.getAddressLine());
}
Run Code Online (Sandbox Code Playgroud)

org.mockito.exceptions.misusing.NullInsteadOfMockException:传递给verify()的参数应该是mock但是为null!

但这种误用不会被抓住:

@Test
public void testBadUseWhen() throws Exception {
  Address mock = Mockito.mock(Address.class);
  Mockito.when(mock.getAddressLine());
}
Run Code Online (Sandbox Code Playgroud)

如果我在这次未被滥用的情况下添加了Mockito的新用法,那么这次我们将获得验证异常:

@Test
public void testBadUseWhen() throws Exception {
    Address mock = Mockito.mock(Address.class); 
    Mockito.when(mock.getAddressLine());
    Mockito.when(mock.getAddressLine());
}
Run Code Online (Sandbox Code Playgroud)

org.mockito.exceptions.misusing.UnfinishedStubbingException:此处检测到未完成的存根

它将针对Mockito.when(mock.getAddressLine());调用的第二个语句引发,但该异常将引用Mockito.when(mock.getAddressLine());调用的第一个语句.

这意味着对于框架的一些不良用途,如果您使用的最后一个mockito方法被错误地使用,您可能会丢失报告信息.

然后javadoc声明:

有时,您可能希望明确验证框架使用情况.例如,其中一个用户希望将validateMockitoUsage()放入他的@After方法中,这样他就会立即知道何时滥用Mockito.如果没有它,他会在下次使用框架之前就知道它.在@After中使用validateMockitoUsage()的另一个好处是,jUnit运行器和规则在测试方法中始终会出现故障,而普通的"下次"验证可能会使下一个测试方法失败.但即使JUnit可能会将下一个测试报告为红色,也不要担心它,只需单击异常消息中的可导航堆栈跟踪元素即可立即找到您滥用mockito的位置.

因此,为了避免在测试类中调用的最后一个Mockito方法失去可能的误用,您可以Mockito.validateMockitoUsage()在每个测试方法之后显式调用.

所以这将成功:

@After
public void after() {
    Mockito.validateMockitoUsage();
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是在每次执行测试后使用MockitoJUnitRunner引擎盖下的调用 Mockito.validateMockitoUsage():

@Override
public void testFinished(Description description) throws Exception {
    super.testFinished(description);
    try {
        Mockito.validateMockitoUsage();
    } catch(Throwable t) {
        notifier.fireTestFailure(new Failure(description, t));
    }
}
Run Code Online (Sandbox Code Playgroud)