Android单元测试(二):再来谈谈为何

今天早上8点半坐到桌子前,打开电脑,看了几分钟体育新闻,作其余一些准备工做,到9点开始真正开始着手写这篇文章。因而开始google,找资料,打算列一大段堂而皇之的理由,来讲明为何要写单元测试,好比:android

  • 对软件质量的提高git

  • 方便重构程序员

  • 节约时间github

  • 提高代码设计安全

  • 。。。网络

等等等等。app

然而我发现上面提到的几点,都不是很好解释。首先,我并无具体的数据,来讲明有了单元测试,咱们的app crash率降了多少,bug少了多少等等。这种东西首先咱们没有去衡量,由于单元测试的增长是按部就班的,每一个版本的迭代增长一点点。很难,咱们也没有,去先后对比。再次,crash率的下降和bug的减小,也难以证实就是单元测试的做用。另外,像重构这种理由,怎么举例证实呢?例子小了显得没有意义,例子大了写起来很困难,读起来也困难。而关于节约时间,我也没有测量过,这个恐怕也很难去测量。只能从理论上去说明,为何能够节约时间,恐怕也很难有说服力的去论述。一样的,对于代码设计的提高,也很难有力的去证实。 框架

更重要的缘由是,上面提到的种种好处,好像其实并非我之因此要写单元测试的直接缘由,更多的,他们像是一种结果。因此若是从列举和证实单元测试的好处这个角度去说明为何要写单元测试的话,我感受甚至很难说服我本身。工具

那就从自身的经历和感觉去说说,我为何要写单元测试吧。其实我之因此要写单元测试,或者说这么喜欢单元测试这种写代码的方式,是出于我自身的缘由,或者说由于自身的一些缺点,让我走上了单元测试这条路,并且不再想回头。单元测试

我为何写单元测试

首先,是由于我不够自信

我相信你们都有接手,或者说参与到一个新项目的经历,也许是由于换了工做,也许是由于职位调动,或其余缘由。当我拿到一个新项目的时候,会有一种坐卧不安的感受,由于一时间比较难理清楚整个app的结构是怎么划分的,各部分各模块之间又是什么样的关系。我怕我改了某一个地方,结果其余一个莫名其妙的地方的受到了影响,而后致使了一个bug。这对于用户群大的app,尤为严重。因此,那种时候就会但愿,若是我改了某个地方,能有个东西告诉我,这个改动影响到哪些地方,这样改是否是有问题的,会不会致使bug。虽然我能够把app启动起来,看看是否是能正常工做,然而一种case能工做,并不表明全部影响到的case都能工做。尤为是在不知道有哪些地方用到了的状况下,我更加难以去遍历全部用到的地方,一个一个去验证这个改动有没有问题。哪怕我知道全部的case,这也是一个很痛苦很费时间的过程,并且不少的外部条件也很难知足,好比说须要什么样的网络条件,须要用户是会员等等。

在这种状况下,单元测试是才是最好的工具。首先,单元测试只是针对一个代码单元写的测试,保证一个代码单元的正确性总比保证整个app的正确性容易吧?遍历一个方法的全部参数和输出状况总比遍历一个app的全部用户场景容易吧?跑一次单元测试总比运行一次app快吧?

所以,在改现有的代码以前,我会先对要改的代码单元作好隔离,写好测试,再去改,改好之后跑一边单元测试,验证他们依然是经过的,这时候我才有信心,将代码合并进去。

一样的状况会发生在重构的时候,我是一个对烂代码不大有忍受能力的人,看到很差的代码,我会忍不住想要去重构,否则的话,没有办法写新的代码。而重构就会有风险。由于我不够自信,重构的时候,也会有一种坐卧不安的感受。这时候若是有完备的单元测试的话,我就能知道个人此次重构到底破坏了哪些地方,是否是对的,这样相对来讲,就会放心的多了。

所以,想用单元测试来保证代码的正确性,这个是我喜欢写单元测试的重要缘由之一。

再次,是由于我没有耐心

对于有必定经验,有必定代码思想的人来讲,当他拿到一个新的需求,他会先想一想代码的结构,应该有那些类,那些组件,什么责任应该划分到哪里去,而后才开始动手写代码,这个是很天然的一个思惟过程。然而在不写单元测试的状况下,咱们可能要把整个feature都作完整,从model到controller(或Presenter、ViewModel)到view到util等等,一整套流程作下来,到最后才可能运行起来看看是否是对的,有的时候哪怕全部代码都写完了,也不必定能验证是否是对的,好比说后台尚未ready等等。总之,在没有单元测试的状况下,咱们须要等到最后一刻才能手动验证代码是否是对的,而后发现原来这里错了一点,那里少了一点,而后一遍一遍的把app运行起来,改一点运行一遍。。。

当我开始写单元测试以后,我发现这个过程实在是太漫长了,我喜欢写完一部分功能独立的代码,就能马上看到他们是否是正确的。若是不是的话,我能够马上就改正,而不用等到全部代码都写完整。要达到这点,那就只有写单元测试了。

固然,哪怕有单元测试,最后仍是要作一遍手动测试工做,然而由于前面我已经保证每个单元都是对的,最后只不过是验证每一部分都是正确的串联起来了而已,这点相对来讲,是很容易的。因此最后所须要的手动测试,能够少不少,顺利不少,也简单得多。

最后,是由于我懒

如前所述,若是没有单元测试的话,那就只有手工测试,把app运行起来,若是有错的话,改一点东西,再运行起来。。。这个过程太漫长太痛苦,对于一个很懒的人来讲,若是能写代码来代替手工测试,每次写完代码只须要按一次快捷键,就能够直接在IDE里面看到结果,那是多爽的一件事!因此冲着这点,我也不想回头。

我记得上一次使用“把app运行起来”这种开发方式,仍是由于调试一个动画效果。由于动画效果是很难单元测试的,那就只有改一点代码,跑一边app,以为不对,再改一点,跑一边,这样来来回回反反复复,那感受真是。。。

单元测试给我带来了什么

前面讲了为何我要写单元测试的缘由,接下来说讲用了单元测试这种写代码的方式之后,给我带来什么样的好处。这根前面讲的“缘由”有部分重合的地方,然而也有不同的地方。

更快的结果反馈

这点前面讲过了,有单元测试的帮助,我能够写完一个独立的代码单元,就马上验证它的正确性,这跟须要完成全部代码再把app运行起来手动测试相比,是一个更快的反馈循环,能更快的发现代码是否正确,也更快的获得一种成就感。

更少的bug,或者说更快的发现bug

正如上面所说,咱们没有作这样的先后统计,来证实有了单元测试之后,咱们app的bug少了多少。然而,我本身的经验是,我已经不知道多少次觉得只是作了一点小改动,不会有任何问题,结果一跑单元测试,发现仍是改出问题来了。从这点来讲,单元测试帮助我发现了很多问题,至少是更快的发现了问题。不少时候,这些问题是由于不当心疏忽了而致使的。然而话说回来,大部分bug不都是由于不当心疏忽了,不少状况考虑到,或者是考虑错了而致使的吗?

你或许会以为,本身很厉害很专业,必定不会有这种“疏忽”,写的代码必定是没有bug的。然而事实是,再厉害的人,都有状态很差的时候,都有情绪不高的时候,都有感受比较累的时候,都会受到或多或少外界的干扰,这种时候都是很容易犯错的。这个跟厉不厉害,专不专业其实没有关系。李世石多么专业,在跟AlphaGo比赛的时候,不是依然会失误,会犯错吗?这个时候若是有那么一层保障,来防止你不当心犯错,岂不是更好的一件事情?

节约时间

对于安卓开发来讲,一遍一遍的运行app,再执行相应的用户操做,看界面是否显示正确的结果,经过这种方式来测试本身的新代码、重构是不是正确的,这是很是浪费时间的一件事情,并且效果还很差。有了单元测试,我如今开发过程当中几乎已经不用把app运行起来了,速度相对来讲快多了。

此外,由于单元测试能帮我减小bug,从而也减小了调试bug,fix bug的时间。一个切身感觉是,自从开始写单元测试之后,我启动AndroidStudio的debugger的次数明显减小了。这也是单元测试节约时间的地方。

固然,这个结论也是自我感受的结果。写单元测试须要时间,这也是不可否认的事情,至于有单元测试是否真的更快,快了多少,我没有具体的统计数据,因此很难给出一个确切的答案。

这里须要重点说一下的是,你为新代码写的单元测试,不只仅是能在目前你此次写新代码的时候起了做用,它的做用更体如今之后重构代码的时候,你能够很快速,很安全的进行重构。这点每每你们会忽略,因此会以为在单元测试上花费的时间“不值得”。

更好的设计

当你为本身的代码写单元测试的时候,尤为是采用TDD的方式,你会很自觉地把每一个类写的比较小,功能单一,这是软件设计里面很重要的SRP原则。此外,你能把每一个功能职责分配的很清楚,而不是把一堆代码都塞到一个类里面(好比Activity)。你会不自觉的更偏向于采用组合,而不是继承的方式去写代码。这些都是很好的一些代码实践。

至于为何TDD可以改善代码的设计,网上有不少的文章去分析和论证这个结论。我看到比较印象深入的一句话是(具体在哪看的搜不出来了):当你TDD的时候,你是从一开始,就从一个代码的使用者,或者说维护者的角度,去写你的代码。这样写出来的代码,天然会有更好的设计。

更强的自信心

有单元测试来保证你的代码是对的,这对于你写代码、发布代码、重构都提供了信心保证,没有那么多的担忧,从而工做起来也更快乐更开心。作人呐,最重要的是开心。。。

而开心,也能让你变成一个更好的程序员。

没有时间写单元测试?

前面大概讲了讲我为何要写单元测试,以及单元测试给我带来的好处,这些其实若是你们去google “why unit testing”,估计会获得相似的答案,然而依然会有不少人不写单元测试。若是问为何的话,那么获得最多的回答,估计是:没有时间。

那么,写单元测试真的须要不少时间吗?为何多数真正写过单元测试的人会说,写单元测试能够节约时间呢?在这里,首先要认可两点。。。

1. 单元测试,的确是一门须要学习的技术。

不只须要学习,并且你要学习的东西还真很多,你要学习JUnit的使用,你要学习Mokito的使用,Robolectric的使用,依赖注入的概念和使用等等等待。此外,在刚开始的时候,你的确也会遇到不少坑,现有代码的坑,Android的坑,Robolectric的坑等等。这个在安卓开发这边显得更是如此,由于Android开发环境是公认的最不利用写单元测试的环境之一。你须要花一些时间去学习如何处理,或者是绕过这些坑。

2. 在一个现有的,没有单元测试的项目里面加入单元测试,会须要一段时间的调整。

一个有单元测试的项目,跟一个没有单元测试的项目相比,结构会有比较大的不一样。所以刚开始,你会发现各类不顺利的状况,你须要去调整各部分的代码,让他们变的容易测试,这也是比较花时间的地方。

这种调整值得吗?我认为是值得的,由于容易测试的项目,每每意味着更灵活,更具有扩展性,这个前面已经提到过了。因此自己这件事情就是一件值得作的事情,更况且,测试自己又是一件很是有价值的事情。

然而等跨过了这两道坎,单元测试还须要花不少时间吗?根据我本身的经验,我以为其实不是这样的,由于等你熟悉了如何写单元测试之后,要对一个类、一个接口写单元测试,是很容易的一件事情。若是你发现一个类很差测,每每是由于这个类的设计是有问题的。此外,你能够慢慢的搭建本身的一套测试框架,简化一些经常使用的繁琐的写法,让写单元测试变得更简便快捷。再加上前面讲述的缘由,整体来讲,我以为写单元测试非但不会须要跟多时间,反而会节约时间。

小结

这篇文章简单讲述了,为何要写单元测试。其实,单元测试的必要性,看看那个知名的程序员必看书单就知道了。在前20本中,全部5本讲述“如何写出更好的代码”的书,无一例外都强调单元测试的必要性。

  • Code Complete

  • The Pragmatic Programmer

  • Refactoring: Improving the Design of Existing Code

  • Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin

  • Working Effectively with Legacy Code by Michael C. Feathers

但愿这篇文章,能让你多一点学习和实践单元测试的决心,由于这真的是很是值得拥有的一项技能,只是刚开始的时候,须要多一点点时间而已。

最后,若是你也对安卓单元测试感兴趣的话,欢迎加入咱们的交流群:

参考连接:What is the single most influential book every programmer should read?

做者 小创 更多文章 | Github | 公众号

相关文章
相关标签/搜索