天天看点

Mockito 简明教程

mock 测试是单元测试的重要方法之一。本文介绍了基于 java 语言的 mock 测试框架 -- mockito 的使用。

mock 测试就是在测试过程中,对于某些不容易构造(如 httpservletrequest 必须在servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 jdbc 中的resultset 对象),用一个虚拟的对象(mock 对象)来创建以便测试的测试方法。

mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

比如一段代码有这样的依赖:

Mockito 简明教程

当我们需要测试a类的时候,如果没有 mock,则我们需要把整个依赖树都构建出来,而使用 mock 的话就可以将结构分解开,像下面这样:

Mockito 简明教程

真实对象具有不可确定的行为,产生不可预测的效果,(如:股票行情,天气预报) 真实对象很难被创建的 真实对象的某些行为很难被触发 真实对象实际上还不存在的(和其他开发小组或者和新的硬件打交道)等等

使用一个接口来描述这个对象 在产品代码中实现这个接口 在测试代码中实现这个接口 在被测试代码中只是通过接口来引用对象,所以它不知道这个引用的对象是真实对象,还是 mock 对象。

关于这些框架的比较,不是本文的重点。本文着重介绍 mockito 的使用。

mockito 拥有的非常少的 api,所有开始使用 mockito,几乎没有时间成本。因为只有一种创造 mock 的方式。只要记住,在执行前 stub,而后在交互中验证。你很快就会发现这样 tdd java 代码是多么自然。

可以 mock 具体类而不单止是接口

一点注解语法糖 - <code>@mock</code>

干净的验证错误是 - 点击堆栈跟踪,看看在测试中的失败验证;点击异常的原因来导航到代码中的实际互动。堆栈跟踪总是干干净净。

允许灵活有序的验证(例如:你任意有序 <code>verify</code>,而不是每一个单独的交互)

支持“详细的用户号码的时间”以及“至少一​​次”验证

灵活的验证或使用参数匹配器的 stub (<code>anyobject()</code>,<code>anystring()</code> 或 <code>refeq()</code> 用于基于反射的相等匹配)

gradle 用户可以使用:

一旦创建 mock 将会记得所有的交互。你可以选择验证你感兴趣的任何交互

默认情况下,所有方法都会返回值,一个 mock 将返回要么 null,一个原始/基本类型的包装值或适当的空集。例如,对于一个 int/integer 就是 0,而对于 boolean/boolean 就是 false。

stubbing 可以被覆盖。

一旦 stub,该方法将始终返回一个 stub 的值,无论它有多少次被调用。

最后的 stubbing 是很重要的 - 当你使用相同的参数 stub 多次同样的方法。换句话说:stubbing 的顺序是重要的,但它唯一有意义的却很少,例如当 stubbing 完全相同的方法调用,或者有时当参数匹配器的使用,等等。

mockito 验证参数值使用 java 方式:通过使用 equals() 方法。有时,当需要额外的灵活性,可以使用参数匹配器:

如果你正在使用参数的匹配,所有的参数都由匹配器来提供。

下面的示例演示验证,但同样适用于 stubbing:

times(1) 是默认的,因此,使用的 times(1) 可以显示的省略。

有序验证是为了灵活 - 你不必一个接一个验证所有的交互。

此外,您还可以通过创建 inorder 对象传递只与有序验证相关的 mock 。

注意:不建议 verifynomoreinteractions() 在每个测试方法中使用。 verifynomoreinteractions() 是从交互测试工具包一个方便的断言。只有与它的相关时才使用它。滥用它导致难以维护。

最小化可重用 mock 创建代码

使测试类更加可读性

使验证错误更加易读,因为字段名称用于唯一识别 mock

public class articlemanagertest {

在基础类或者测试 runner 里面,使用如下:

下面是一个精简版本:

然而,这是不包括在最初的 mockito 另一个有争议的功能。我们建议您只需用thenreturn() 或 thenthrow() 来 stubbing ,这在测试/测试驱动中应用简洁与简单的代码足够了。但是,如果你有一个需要 stub 到泛型 answer 接口,这里是一个例子:

stubbing void 方法,需要不同的 when(object) ,因为编译器不喜欢括号内无效的方法...

在 用于 stubbing void 方法中,dothrow(throwable...) 取代 stubvoid(object)。主要原因是提高可读性和与 doanswer() 保持一致性。

当你想用 stub void 方法 使用 dothrow():

在调用 when() 的相应地方可以使用 othrow(), doanswer(), donothing(), doreturn() 和 docallrealmethod(),当:

stub void 方法

stub 方法在 spy 对象(见下面)

可以不止一次的 stub 相同的方法,在测试的中期来改变 mock 的行为

但你更加倾向于使用这些方法来代替 when(),在所有的 stubbing 调用。可以阅读更多关于这些方法的描述:

<a href="http://martinfowler.com/articles/mocksarentstubs.html">http://martinfowler.com/articles/mocksarentstubs.html</a>

<a href="http://mockito.org/">http://mockito.org/</a>