前言
适用人群:刚接触单元测试不久的小伙伴们。
本文章的关注点不在于如何使用各种Mock框架(如Mockito、PowerMockito、MockMvc),基本用法非常简单,网上也很多教程,基本属于一看就会系列;本文的出发点在于我第一次接触Mockito的时候,所有人都说用来做单元测试,用来解决外部依赖没开发完成的问题,而我期间产生了一系列疑问,实在不知道Mockito的意义所在,后来在项目中多次用到后逐渐明白,所以以此文记录一下。
情景
假设一个最简单的情景,就是你要开发一个插入数据的接口,那么插入之前必须是先登陆的,所以伪代码大概如下:
public boolean insert(String someData)
if(isLogin(currentUser)){
return doInsert(someData);
}
这是一个非常非常简单的功能了,你负责的核心功能在于doInsert(somedata)里与数据库的交互动作,然后你想测试一下你的这个接口行不行,但是你现在有一个问题:
你只是负责这个功能模块而已(如订单信息,那么该功能就是插入订单信息),登陆模块不是你负责的而且正在待开发而且是以微服务独立存在,所以isLogin(currentUser)是一个外部请求的RPC接口,这时候正常来说你是得等别人开发完你才能进行测试
解决
从上面的情景能看出来,你可以尝试去编写这个接口的单元测试用例,你会发现怎么样都得等待别人开发完,这时候Mockito的作用就来了,我们能用它把isLogin(currentUser)这个方法进行模拟,让它直接返回true就行了,那就不用等别人开发完了就可以进行测试了。
疑问
这样仿佛把用途说清楚了,但是看起来这样的用途有点怪怪的,总感觉是不是有点鸡肋呢,然后可能有人会不禁产生以下的疑问:
一.我直接不要if()判断语句就好了,到时候测试完再加上去
这样当然是不可取的,原因主要有两点:
(1)这只是上面的这么简短的代码,要是代码非常多非常复杂,你要改动的地方就不是这么少了,改过来然后改回去会耗费不少时间不说,还有可能出错,忘记改回去的地方那就惨了
(2)第一条还能以“人力”来把控,但是有些项目是要做持续集成CI的,即在代码集成的时候会触发自动化测试,即你所写的测试用例要跑起来,所以你提交代码的时候是要保证代码是正确的而且测试用例还能没问题,显然以上这种“曲线救国”是不能同时保证代码正确且测试用例也能跑(设想以上场景,为了测试,把if判断isLogin都删了,代码正确就破坏了)
二.那isLogin()也是一个功能呀,这个接口本身就包括了isLogin(),那么模拟它返回true那也不是完整的测试呀,isLogin也有可能错呀
这个想法是对的,但得看你的关注点是什么,因为你想关注的就是你所开发的插入功能那一段代码能不能在正常运作,而去先屏蔽了isLogin,所以假设测试过没问题,得到的结论就是并不一定保证insert()这个接口完全正确,但是能保证除了isLogin这个RPC接口外都是正确的。
但其实isLogin这个接口作为一个外部调用RPC接口,你只要发请求的代码没写错,那么对于你自己所负责的模块而言就是对的,因为这个判断是否登陆的具体逻辑是别人所负责的。
总结
一众Mock框架的应用场景主要在于模拟外部RPC接口,让它返回你想要的数据,另外当然也能模拟自己负责但尚未完成的接口的,但是要注意的是对谁模拟了,只是保障了被模拟接口外的其他代码是正确的,也要想办法去保证被模拟接口的正确