单元测试的前世今生 与sonarqube的爱恨纠葛 写给小白看,小白可以看到一些技术,会有收获 大神请留言请吐槽指点一二 谢谢!

单元测试,问问自己写不写单元测试?

其实,工作10年了,都没有专门写单元测试,野路子写了这么多代码,即没有单元测试,也没有sonarqube,不知道留下了多少Bug在这10年的职场之路!有没有在入住酒店的时候,发现系统卡死了,有木有在银行开户的时候系统… …很开心是吧!

第一次写单元测试的时候,老把测试驱动开发混在一起。第一次看到powermock出来的单元测试代码,都想吐。这代码看起来真心的“恶心”至极。10行代码,也许得造100行单元测试代码出来,这可能说得稍微有些夸张,就是单元测试代码量超级多的感受。如果要实现100%的单元测试,简单会是一个极大的挑战。代码量会指数级增加。

关键词:Powermock

写单元测试,我说的是java,我们使用powermock、mock、testng这种东东,相信你知道怎么去了解更加详细的信息。这里就不帖一些没有态度没有温度没有人文感受的文字过来了。

秀几行

UserBean user = mock(UserBean.class);when(user.getUserById(anyInt())).thenReturn(new UserBean());doNothing().when(user).sayHello();

这是最常用的几行代码,基本上就是依靠他们,模拟所有代码行为进行单元测试。

恶心?

是的,第一次见到他们,不恶心才怪,得一点一点mock,对于静态类等特殊的成员,还得找法子去mock,把每个分支都覆盖到,最后实现100%的覆盖率。

单元测试的意义

之前我的感觉是单元测试是帮我们找出当前代码问题,而写完单元测试之后,到没有这种感觉,反而是,防止今后别人不小心破坏了当前已经验收通过的代码。如果按我们写mock的方式进行全面覆盖的话,别人只要改变一个逻辑,都可能导致单元测试失败,从而发现风险。

单元测试的权衡

因为我们只要求单元测试在service层实现100%的覆盖,所以我会爱上,单元测试,如果要在bll层,覆盖的话,我可能会改变哦。bll层太多的细枝末节,mock起来遇到一股意想不到的代码风暴。而service层则不同,对于我们来讲,service层是负责组装的,mock的时候就能巧妙的实现快速覆盖,避免mock中常见的特殊的静态类啊,还可以避免过多的if要覆盖。如果想要挑战自己的单元测试实力,那就是去写bll层的单元测试,嗯,相信是史无前例的挑战!

单元测试与sonarqube相爱相杀

单元测试要覆盖所有的逻辑分支,按copy复制再修改修改的写法,重复代码会直接捅破sonarqube的底线,直接不给过啊,重复率太高了。写单元测试的时候,都有种冲突,把sonarqube关掉,哈哈!不关sonarqube,那就得重用重用自己的代码,不能复杂一口气复制一遍testcase出来。

一招让单元测试powermock与sonarqube和平相处

单元测试可以看着源代码,一点一点mock,遇到一个if就给个开关控制,一路下来,就产生了很多开关,这样子就能通过参数来控制一个公用的testcase实现全分支覆盖,同时又不会引起powermock报警。

秀一下伪代码

@Test[name="登陆失败-验证码错误",enable=true]public void login_whenVerifyCodeError_thenFailed(){  login(false,false,false,false,false,verifyMessage);}@Test[name="登陆失败-帐号锁定",enable=true]public void login_whenAccoutLocked_thenFaild(){    login(true,false,false,false,false,verifyMessage);}... ...private void login(boolean isVerifyCodeOk,boolean isAccountLocked,...){ when(verifyAgent.check(verifyCode)).thenReturn(isVerifyCodeOk); ....}

这段伪代码是秀出最近摸索出来的,用来防止单元测试出现大量重复代码。通过传参,控制代码分支走向,达到即能覆盖到所有支付,又不会惹恼sonarqube.

巧用只在Service层写单元测试原则

service层写单元测试,也就是把琐碎的具体的业务代码放到bll层,service层保持一种组装bll业务的对单元测试友好的状态,就可以巧妙的避免写复杂的service层单元测试。为了,能快速搞定单元测试,这个原则可以合理的利用利用。还有一些小经验:

  1. 尽量不要把些特殊的类丢到Service层来使用,比如一些静态类,final类,方法什么 ,可以找静态类相关的mock方式,但是如果不把他们放进来,是不是直接可以绕过去?是好是坏呢?欢迎指点指点。如果从Service组装业务的定位来看,是可以的,把业务验证丢到bll层,这样子service层拿到一个bll层返回的业务结果,也巧妙的避免了用单元测试最可能出现代码大爆炸的地方。不好的是,可能在业务细节覆盖上就失去了精度。这种精度覆盖的放弃 ,也许也算是一件好事,不然,每写一点点代码,都可能导致大量的单元测试代码成本。
  2. 在service层避免try catch,单元测试不好搞,目前没有找到好方式把try catch丢给bll层,或者不要try,直接往外丢。往bll层放,也不错,返回一个明确的结果,就好进行单元测试覆盖。往外抛,不要try catch。一出现try catch,单元测试覆盖就显示尴尬了,有经验的可以分享分享。
  3. 发现service层不好进行单元测试的,就要思考,这些代码放在serivce层是否合适了,打包成一个小业务放到bll层。嘻嘻,你会发现,写单元测试真的好快.都把复杂性绕过去了。酱油党强力推荐,不要打我~

 

技术岛公众号
技术岛公众号

发表评论

电子邮件地址不会被公开。 必填项已用*标注