聊聊单元测试这事——为什么要写单元测试?
单元测试的重要性
工作写代码这么多年,越发感觉单元测试的重要性。
主要有几个原因:
- 再牛逼的人,也不能保证说自己写的代码不会有问题,总得有个验证功能正确性的过程。
- 写过的代码未来可能出于某些原因需要做改动或者重构,需要保证改动或重构后不影响原有代码的部分或全部功能。
- 有专门的测试人员测试代码,但他们或因不了解全部的实现细节,测试范围无法完全覆盖。
- 有合理、全面的测试代码在把关,后续更改业务代码时对开发人员有安全感。
- 快速发现错误,减少调试的时间。
单元测试怎么就流行不起来?
单元测试有诸多好处,或者说可以帮忙避免很多问题,但为什么就没有成为开发人员的常规行为呢?
原因我个人总结来也有几个:
- 从上到下没有重视,团队常常以项目周期短,资源紧张为由裁剪掉这一步骤。
- 过于依赖测试部门,就算问题在生产上暴露了,也可以让测试人员背主要的锅。
- 开发人员觉得写测试代码繁琐,倾向于直接写完业务代码再说,然后就没有然后了。
写到这里我想问一句:代码的质量不是应该由写程序员自己负责的吗?写出没有缺陷的代码不是程序员该追求的目标之一吗?
避重就轻,忙于救火
工作上我发现不少同事的工作时间和精力都耗费在处理生产问题上了,一天折腾忙活下来感觉很充实,但其实这些都是大可不必的。虽然导致出现生产问题的原因有很多,但如果程序代码说这一点也不关它事,我是不能接受的。“千里之堤,毁于蚁穴”,这些大部分原本可以扼杀在源头而不因出现在此处的问题,却因前期一时图快、省事忽略而被放大,以至于现在需要耗费更多的资源去处理,或者说是去弥补。
编写配套的单元测试代码就可以很好地避免上面的问题,而且是"从娃娃抓起",问题成本相对低了许多,绝对是受益良多的事情。
写测试代码感到枯燥不堪?
至于觉得写测试代码繁琐枯燥,体现不出工作量,你可以这样去认为:
- 你所写的每一行测试代码,在未来都是可以重复运行的,每次运行都可以验证一次目标代码的正确性。
- 每次为目标代码新增一条测试案例,就意味着通过该测试案例的代码变得更完善、更健壮。
- 现在写测试代码是为了自己在未来某一天可以轻松地修改或优化代码。
如果你会这样去想,就会觉得写测试代码有意义多了。
其实,单元测试只是一种意识
我相信不少程序员在写代码时偶尔都会写一个小Demo简单地先验证一下接口的正确性。在开发中有这种意识,简单如IF-ELSE就可以去验证业务代码,不用过于纠结引入何种测试框架,甚至是为了写测试代码而先徒手撸出一个测试框架来(先累为敬~)。
测试框架
而且现在也不缺一些功能完善、使用友好的测试框架,因为笔者目前工作使用的语言是C/C++,所以稍微列举一些主流的测试框架。
- MinUnit:两行语句实现单元测试框架
- Catch2:项目中仅需引用一个头文件,该头文件集成了测试框架所需的所有内容
- Google Test:Google 出品,可以结合
GMock
使用,功能更为健全 - Boost Test:如果项目中大量使用Boost的其他模块,那么测试框架也一并用上吧
- CppUnit:支持Windows和Linux,通过继承并实现框架提供的测试基类实现案例注册
- CXXTest
纠结的问题
-
测试代码要不要与产品代码放在一起?
最近公司对已有产品的代码进行改造,一直都没有测试代码,计划在改造前将其补上,而因为设计的问题,模块之间的耦合比较紧密,往往实例化一个对象需要先实例化很多其他对象。在实施的过程中,因接口依赖比较严重,不得不将一些测试代码写到功能代码里,这是我不愿意看到的。不知各位看友是否有好的解决办法?
-
测试覆盖率能保证代码的质量吗?
我认为这是显然不能的。自己写自测案例总是不免要过自己的那一关。“循规蹈矩”的测试案例写再多也没意义;而写一些“意料之外”的测试案例总是会小心翼翼。特别是在写完业务代码再写对应的测试案例的时候,思维定势的现象就表现出来的——你写的测试案例总是跳不出你写的业务代码逻辑,不然的话在写业务代码时你怎么没想到呢?
结束
这篇先点题到这里,后面再根据自己的经验阐述如何写单元测试,何为好的单元测试。
更多内容请关注个人微信公众号 物役记 (微信号:materialchains)