形成Mockito"语法"

IAm*_*aja 40 java junit unit-testing mocking mockito

Mockito似乎是一个非常甜蜜的Java存根/模拟框架.唯一的问题是我找不到关于使用API​​的最佳方法的任何具体文档.测试中使用的常用方法包括:

doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber
Run Code Online (Sandbox Code Playgroud)

当你在实践中看到Mockito的例子时,你会看到如下代码:

when(yourMethod()).thenReturn(5);
Run Code Online (Sandbox Code Playgroud)

从我读过的所有文档中,我已经确定了Mockito"语法"的几个"模式",它们是通过菊花链式连接这些方法调用获得的,就像上面的例子一样.我发现的一些常见模式是:

当/ Then: when(yourMethod()).thenReturn(5);

给定/将:给定(yourMethod()).willThrow(OutOfMemoryException.class);

Do/When: doReturn(7).when(yourMock.fizzBu​​zz());

Will/Given/Do: willReturn(any()).given(yourMethod()).doNothing();

验证/执行:验证(yourMethod()).doThrow(SomeException.class);

我正在窒息的是如何选择正确的模式/方法调用组合来模拟我的测试用例.看起来你可以在看似无穷无尽的组合中将它们连接在一起,我不确定哪种模式适合哪个问题.

一些Mockito Guru可以帮助阐明Mockito方法的哪些模式/组合用于哪种类型的测试用例(以及为什么)?提前致谢!

Daw*_*ica 32

有一些缺点when/thenReturn,when/thenThrowwhen/then语法.例如,

  • 在这种情况下when/thenReturn,如果返回类型是带通配符的泛型,并且您希望返回相同类型的模拟,则无法避免编译警告.
  • 你不能使用when/thenThrowwhen/then用于void方法.
  • 你不能在Mockito间谍上使用这些语法.
  • when除非你调用resetmock ,否则你只能为模拟对象,方法和参数的每个组合调用一次.
  • when当您使用参数匹配器时,为模拟对象和方法的一个组合调用多次可能会导致问题.

我发现这些案件很难记住.因此,而不是试图保持的时候赛道 when/thenReturn,when/thenThrowwhen/then语法都可以了,不行的,我宁愿完全避免它们,赞成doReturn/when,doThrow/whendoAnswer/when替代品.这就是说,因为你偶尔需要doReturn/when,doThrow/when并且doAnswer/when,你可以随时使用这些方法,还有在学习如何使用是没有意义的when/thenReturn,when/thenThrowwhen/then.

需要注意的是doReturn,doThrowdoAnswer可以以同样的方式链接在一起thenReturn,thenThrowthen.他们没有的是在一次调用中返回多个值(或抛出几个异常,或运行几个答案)的选项doReturn,doThrowdoAnswer.但我发现我很少需要这样做,这并不重要.

还有一个缺点doReturn,我认为这是不重要的.您没有像编译时那样检查其参数类型的编译时间when/thenReturn.因此,如果您的参数类型错误,则在运行测试之前不会发现.坦率地说,我不在乎.

总之呢,我已经使用了的Mockito两年多了,我考虑是一致的使用doReturn,doThrow并且doAnswer是一个最好的Mockito实践.其他Mockito用户不同意.

  • 我同意@ david-wallace.可读性非常主观; 一致性不是.编译时类型安全在这里并不重要,因为您的测试会在以后找到它.在这一点上应修改[Mockito docs](http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html#doReturn%28java.lang.Object%29). (3认同)
  • 我发现 `do*/when` 错过的最大的事情是我的 IDE 让我知道更改。如果我更改返回类型(例如,从`List` 到`Set`),所有`when/then` 都会被标记,我知道要更改它们。我不知道这一点,直到测试以 `do*/when` 失败。显然我_将_运行测试,我只是发现它不是一种识别案例的简洁方法,并且可能需要我多次运行它们。 (3认同)
  • 可能只是我个人的看法,`when/then` 对我来说最大的优势是它的可读性。与 `doXxx/when` 相比,它的阅读更加流畅。 (2认同)
  • @AdrianShum我理解你的观点; 我真的.但我发现这两种形式同样可读.我相信它最终归结为你习惯的东西.对于Mockito初学者的开始,我毫不犹豫地推荐do/when形式. (2认同)

Mat*_*att 16

Mockito经常有几种做事方式.

我发现自己主要使用:

// Setup expectations
when(object.method()).thenReturn(value);
when(object.method()).thenThrow(exception);
doThrow(exception).when(object.voidMethod());


// verify things
verify(object, times(2)).method();
verify(object, times(1)).voidMethod();
Run Code Online (Sandbox Code Playgroud)

我发现用这三种电话我可以完成95%的需要.

另外,你使用的是什么版本的Mockito?"给定"和"将"结构不存在于最新版本(1.9.0+)中

但是,有些情况下我希望返回值或异常响应输入.在这种情况下,您可以使用Answer接口检查方法参数并返回适当的值.

public class ReturnFirstArg<T> implements Answer<T> {
    public T answer(InvocationOnMock invocation) {
        return invocation.getArguments()[0];
    }
}

when(object.method(7)).thenAnswer(new ReturnFirstArg<Integer>());
Run Code Online (Sandbox Code Playgroud)

  • 第三行不应该是`.when(object).voidMethod()`吗? (2认同)

Adr*_*hum 8

事实上事情看起来比你想象的要简单得多

参考:http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html

验证:

为了使用Mockito,您需要了解Mockito的一个基本哲学:Stubbing和Verification是分开的.因此,您提到的"验证/执行"实际上正在执行"验证"工作,而其他4个"语法"则用于存根.Stubbing定义模拟对象在不同情况下的反应方式.验证是在先前对被测系统(SUT)的调用中确保按预期调用模拟的内容.

当/然后,给定/将:

然后它来到"何时"和"给定"的家庭.您可以简单地将它们视为彼此的别名."给定"系列在Mockito 1.8.x中添加,以使其看起来更符合BDD实践.

DoXxx:

在正常情况下,我们主要使用when(xxx).then(...)(和given(...).will(...)).但是有些情况下语法不起作用.最明显的情况是当存根方法的返回类型为空时.在这种情况下when(mockObj.voidMethod()).thenThrow(anException)不会编译.作为一种变通方法,创建了Do/When的替代语法,因此您可以将上一行写为doThrow(anException).when(mockObj.voidMethod())