该死的单元测试,写起来到底有多痛?( 三 )

该死的单元测试,写起来到底有多痛?
文章插图
 
里面的 when(xxxx).thenReturn(xxx) ,就是我们指定的 mock 逻辑,这就是指哪打哪,随心所欲 。
我们跑一下,你看就很快,59 ms,也不需要 Spring 框架 。

该死的单元测试,写起来到底有多痛?

文章插图
 
就是通过这样的 mock 手段,忽略了依赖的服务的逻辑,使得我们要它怎样就怎样,便于我们单测类的编写 。
至于具体的 mockito 的使用方式,这篇就不做展开了,网上看看应该简单的 。
然后上面提到的静态方法的模拟,也简单的,我截个网上的例子:
该死的单元测试,写起来到底有多痛?

文章插图
 
上面的逻辑就是模拟静态方法 StaticUtils.name,跟普通对象不同的是它用完之后需要 close 一下,所以用了 try-with-resource,当然也可以手动 close,原理也不做展开,有兴趣的小伙伴可以自己去了解下 。
看到这,想必你对单测应该已经挺有感觉了吧?
道阻且长知道了单测如何写和为什么难写之后,其实我们的思路已经清晰了,但是往往现实还是残酷的 。
以前的老代码,巨多,领导要求补,难!
一个 service 依赖十几个服务,mock 都 mock 傻了,难!
项目太紧急了,从长远来看,单测的收益会使得整体开发和后期维护的时间短,但是领导就是要求下周一上线,难!
我个人认为一些稳定的代码,除非现在真的没事做了,完全没必要去补单测,完全可以在改动对应的点的时候再去补,然后新写的方法都要求上单测,这是非常合理的 。
如果写业务的时候,同步写单测,会促进你的思考,缕清思路,写出的代码因为可测试性高,自然而然就比较漂亮和解耦 。
还有一点也很重要,其实我们写单测的时候,不应该过多的关注内部的逻辑,举个非常简单的加法例子,我们单测只关心 add(1,1) 的结果是 2,我管你里面是的实现到底是位运算还是啥运算?
因为只有当我们的单测没有过度的关心内部实现时,之后方法的具体实现变更(从普通的 +,变成了位运算),我们的单测才不需要进行对应的修改 。
但实际上这种情况对我们业务不太适用 。
举个例子 YesService 之前依赖 yesDao ,现在这个 Dao 被剥离了,变成了另一个 RPC 服务,对应的我们之前所有的测试用例还是需要更改的,这是没办法的事情 。
不过为什么我还要提一下这点呢?
比如你的测试方法里面有个 xxxService.save 逻辑,这个方法没有返回值,后面的逻辑也不依赖它,那么就不要想着在单测是时候写 verify(xxxService.save(..)); 来验证这个方法是否被调用 。
这样验证是否被调用其实意义不是很大,并且之后如果 xxxService 被移除了,单测就抛错了,因为里面没有调用 xxxService.save ,你还需要把这个单测给修复了 。
这就是我所说的,写单测的时候,不要过度关注方法内部实现(有些需要mock的没办法) 。
最后好了,说了这么多,相信你对单测应该有所了解了吧?
最重要的还是对单测有个正确的认识,然后掌握 mock 的技巧,写新方法的时候,尝试设计完接口后,先写下单测,慢慢的你就会有感觉了,在写单测时,你自然而然的会考虑到诸多边界值的处理,你写的代码质量也会提高,渐渐地就会感受到单测的好处 。
很多公司单测之所以推行不下去,就是因为没有一个很好的宣讲,或者说对单测的系统介绍 。
我相信大家都是在一年中的某个月份,领导在会上突然来了一句话:我们接下来要写单测!下个月覆盖率要达到50%!
然后大家就吭哧吭哧开始写了,写么又是抄网上的一些例子,把整个项目一起,就进行集成测试了,然后写着写着,有人把数据库改了,跑的好好地单测就挂了 。
要么就是写死数据,这个月单测是行的,下个月就挂了 。
也没有人告诉你这单元测试写的不对,咱不是说写在 test 包里面的代码就叫单元测试 。
一开始气势汹汹,后面虎头蛇尾,这就是绝大公司执行单测的真实写照 。
领导很心痛,为什么就推不下去,大家都这么不积极,这么没有主人翁精神吗?
下属头痛加手痛,这tm啥玩意啊,是人写的吗?
就这样,每年的某个时刻,你的领导都会突发开始抓单测,然后持续几周或一个月,热情逐渐消退,最后无人问津,领导也假装不知道 。如此往复,年复一年 。


推荐阅读