浅谈 Mockito:Java 单元测试神器

背景

  • 背景
  • Mockito 解决的问题
  • Mockito 的优点
    • 优点 1:简单易用
    • 优点 2:功能强大
    • 优点 3:语法优美
  • 小结

背景

记得刚开始学 Java 那会儿看过一个讲解 Mockito 的视频,当时不理解,感觉这东西不过如此,平时不太会需要用到,就把它忘到九霄云外了。

两年过去了,翻过来看到了同一个视频,这才意识到这东西的重要性!简直就是开发效率提升神器好不好!

两年间,是我的编程习惯发生了天翻地覆的变化。之前的我喜欢学新技术,喜欢把功能快速实现(当然,也是产品的压力在那里),不太在意代码的可维护性,单元测试更是没写过;现在的我则明白了软件开发行业一个很重要的道理:

要想走得快,先得走得稳。
The only way to go fast, is to go well.

(这话是 Robert C. Martin 在《架构整洁之道》里说的。)

简单粗暴地把功能实现,表面上看“走得快”,但其实随着项目变大,要付出更多的维护成本,反而走得慢;如果多花一些时间设计架构和编写测试,把软件拆分成更小、更灵活、更易测试的组件,先保证“走得稳”,那么长期来看反而会走得快。

所以,单元测试是一件常常被忽视,但其实十分关键的事情。

Mockito 解决的问题

众所周知,Java 已经有了 JUnit 这个很好用的单元测试工具。那么 Mockito 替我们解决了什么问题呢?

正如其名字暗示的一样,Mockito 主要解决了 mock 的问题。

简单来说,假设你要测试一个组件 A,而这个组件调用了另一个组件 B 的某方法 someMethod()。这就意味着,你在执行组件 A 的时候,组件 B 的 someMethod() 也会被执行。

在开发中,这种情况当然是无可避免的;但对测试来说,这可不是个好消息!试想如下几种情况:

  • 组件 B 的 someMethod() 涉及网络请求。一方面网络请求不稳定,另一方面该请求需要 token,不可能在每个需要执行单元测试的环境都配置这样的 token;
  • 组件 B 的 someMethod() 涉及用户输入。不可能让用户在单元测试的时候配合输入吧;
  • 组件 B 的 someMethod() 涉及大量计算,占用大量资源。如果这样执行单元测试,显然成本过高;

在这些情况下,如果想单独测试组件 A,更好的做法就是把组件 B “mock” 掉,即用一个假的组件 B 提供假的 someMethod() 方法。这就像是想要测试汽车的安全性,没必要在碰撞实验中用真人吧!用假人就行了。

Mockito 的优点

下面通过几个具体的例子,来看看 Mockito 的优点:

优点 1:简单易用

比如我想测试组件 A 的某个方法 someMethod1,但该方法需要调用组件 B 的 someMethod,如何把它 mock 掉呢?

非常简单:

ComponentA componentA = new ComponentA();
ComponentB componentB = mock(ComponentB.class); // 创建一个 mock 的 componentB
when(componentB.someMethod()).thenReturn("some value");

优点 2:功能强大

比如,我还是想测试组件 A 的某个方法 someMethod1,但该方法需要调用组件 A 自己的 someMethod2,而我想把 someMethod2 mock 掉,可以吗?

可以!借助 Mockito 的 spy 方法就行了:

ComponentA componentA = new ComponentA();
ComponentA spyComponentA = spy(componentA); // 创建一个 spy 对象
doReturn("some value").when(spyComponentA).someMethod2(); // 这样一来,spyComponentA 在调用 componentA 时就会返回 "some value"
assert spyComponentA.someMethod1() == "some other value"; // 测试 someMethod1

是不是非常强大!

优点 3:语法优美

有没有发现,上面用到的 whenthenReturnspydoReturn 都非常简洁?简直以冗长著称的 Java 代码里写出了脚本语言的味道!

它们都是 Mockito 提供的 static import

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.thenReturn;
import static org.mockito.Mockito.when;

小结

这周刚在项目里把 Mockito 用起来了,mock 了一个 API 调用,效果非常好。以后一定会成为一件经常使用的工具。

你可能感兴趣的:(测试,Java,单元测试,java)