单元测试系列一-为什么要写单元测试,何时写,写多细

一、前言

半年前在公司团队内推动单元测试的落地,略有一些心得,记录在此。如有不同观点或建议,请在评论区留言,一起探讨。

定义:单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

单元测试从长期来看,可以提高代码质量,减少维护成本,降低重构难度。但是从短期来看,加大了工作量,对于进度紧张的项目中的开发人员来说,可能会成为不少的负担。

本文从为什么要写单元测试,何时写,写多细这些我们最关心的问题展开讨论,试图解答如何在进度紧张的项目中,通过写有效的单元测试来提高代码质量的问题。

二、单元测试要写多细

酷壳上有篇关于“单元测试要做多细”的文章,文章是从StackOverflow上的一个问题讨论开的。这个问题是–

“TDD需要花时间写测试,而我们一般多少会写一些代码,而第一个测试是测试我的构造函数有没有把这个类的变量都设置对了,这会不会太过分了?
那么,我们写单元测试的这个单元的粒度到底是什么样的?并且,是不是我们的测试测试得多了点?”

点赞最多的答案是–

老板为我的代码付报酬,而不是测试,所以,我对此的价值观是——测试越少越好,少到你对你的代码质量达到了某种自信(我觉得这种的自信标准应该要高于业内的标准,

当然,这种自信也可能是种自大)。如果我的编码生涯中不会犯这种典型的错误(如:在构造函数中设了个错误的值),那我就不会测试它。我倾向于去对那些有意义的错误

做测试,所以,我对一些比较复杂的条件逻辑会异常地小心。当在一个团队中,我会非常小心的测试那些会让团队容易出错的代码。

这个答案给人感觉对单元测试持一定的否定态度和不感冒态度,但是这一最佳答案的回答者是Kent Beck!正是那位极限编程、测试驱动开发和单元测试以及JUnit的创造者Kent Beck。Kent Beck的答案,正好回答了单元测试要写到什么程度这个问题。单元测试不是越多越好,而是越有效越好!进一步解读就是哪些代码需要有单元测试覆盖:
1. 逻辑复杂的
2. 容易出错的
3. 不易理解的,即使是自己过段时间也会遗忘的,看不懂自己的代码,单元测试代码有助于理解代码的功能和需求
4. 公共代码。比如自定义的所有http请求都会经过的拦截器;工具类等。
5. 核心业务代码。一个产品里最核心最有业务价值的代码应该要有较高的单元测试覆盖率。

三、何时写单元测试

写单元测试的时机不外乎三种情况:

(1)一是在具体实现代码之前,这是测试驱动开发(TDD)所提倡的;

(2)二是与具体实现代码同步进行。先写少量功能代码,紧接着写单元测试(重复这两个过程,直到完成功能代码开发)。其实这种方案跟第一种已经很接近,基本上功能代码开发完,单元测试也差不多完成了。

(3)三是编写完功能代码再写单元测试。我的实践经验告诉我,事后编写的单元测试“粒度”都比较粗。对同样的功能代码,采取前两种方案的结果可能是用10个“小”的单测来覆盖,每个单测比较简单易懂,可读性可维护性都比较好(重构时单测的改动不大);而第三种方案写的单测,往往是用1个“大”的单测来覆盖,这个单测逻辑就比较复杂,因为它要测的东西很多,可读性可维护性就比较差。

建议:我个人是比较推荐单元测试与具体实现代码同步进行这个方案的。只有对需求有一定的理解后才能知道什么是代码的正确性,才能写出有效的单元测试来验证正确性,而能写出一些功能代码则说明对需求有一定理解了。

四、为什么要写单元测试

这其实是问单元测试能带来什么好处。之所以把这个问题放在最后讨论是因为如果一上来就说单元测试多好多好,终究还是会缺乏说服力。

而有了上面讨论做铺垫,我们更加清楚单元测试的使用场景,以及它做得到和做不到的。

单元测试的作用:

(1)让我们对自己的代码有信心

修改了代码后单测依然通过的,起码说明我们的修改没有破坏程序的正确性。这从主观上能增加我们对代码的信心。虽然单元测试通过了并不意味着程序就没有bug了,但我们也要了解到这可能不是单元测试的问题。单元测试顾名思义是测试一个”单元”,这个”单元”一般是类或方法,而不是整个系统。对整个系统的测试那是集成测试,功能测试的职责。单元测试追求的是快速反馈,频繁执行。集成测试虽然测“全局”,但成本较高,所以执行频率较少。两者使用场景不同,目的不同。

2)为代码重构保驾护航

看到代码很差劲,想重构,但又担心重构之后出问题,怎么办呢?如果有单元测试情况就不一样了,重构完代码,跑一遍单元测试,如果单元测试都通过,基本上可以保证我们的重构没有破坏原来代码逻辑的正确性。不过前提是之前的写的单元测试质量很好,覆盖率很高。当然这仅限于小范围的重构,比如重构一个类或者函数的实现,但对于大刀阔斧的重构(比如单体重构成微服务,面向库表模式重构成DDD),就不适用,那个时候要重写单元测试了。

(3)通过单元测试快速熟悉代码

单元测试不仅起到了测试的作用,还是一种很好的“文档”,通过单元测试,我们不需要深入的阅读代码,便能知道这段代码做什么工作,有哪些特殊情况需要考虑,包含哪些业务。

五、小结

  • 何时写
    单元测试与具体实现代码同时进行。

  • 写多细
    哪些代码需要有单元测试覆盖:
    1、逻辑复杂的
    2、容易出错的
    3、不易理解的,即使是自己过段时间也会遗忘的,看不懂自己的代码,单元测试代码有助于理解代码的功能和需求
    4、公共代码。比如自定义的所有http请求都会经过的拦截器;工具类等。
    5、 核心业务代码。一个产品里最核心最有业务价值的代码应该要有较高的单元测试覆盖率。

  • 14
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值