我对单元测试和测试驱动开发的见解
之前写了关于NUnit和JustMock的介绍,我们都知道这只是单元测试的工具,最终还得回归理论。
什么是单元测试
(废话想说一些:如果我们听到一个陌生的概念,不去追问它是什么,它有什么用?直接进行任务去完成这个概念描述的事,那么,我们可能很难理解我们为什么要这么做,也可能做不好。)
- 概念解释
单元测试是针对一个工作单元设计的测试。这里的工作单元一般是指对一个方法的一个要求。 - 单元测试优点
我们可以集中精力针对于一个特定的工作单元进行测试,排除其它逻辑干扰,使编写测试更加容易。如果测试失败,也能很快锁定哪里出现缺陷。 - 单元测试的特征
- 与其它代码隔离:单元测试代码不影响其它代码,需建立独立项目文件;
- 与其他开发人员隔离:每个开发人员编写的单元测试不互相干扰;
- 有针对性:单元测试是针对一个特定的工作单元编写的;
- 可重复:单元测试可以重复运行,并且保证每次结果都正确;
- 可预测:能够确定方法输入X,将返回Y。
阻碍开发人员编写单元测试可能的原因
大部分公司即使要求编写单元测试也是先写业务代码,再编写测试代码去测试。由于开发人员水平不齐,业务代码不能保证质量,可能导致难以测试。我收集了经常遇到一些阻碍测试的问题。
- 依赖其它类
- 业务逻辑没有返回值,直接影响数据库或者其它
- 业务逻辑复杂,需要很多验证
- 其它外部资源:数据库、文件、配置、缓存等
当然还有很多情况阻止着我们编写单元测试。解决的办法遵循三个点:
一是编写业务代码严格执行单一职责原则;
二是面向接口编程,使用依赖注入;
三是利用工具模拟外部资源。
== 另外一点 ==
我们总将一些静态资源封装成静态类,当这些类也参与业务逻辑,那么就会影响编写单元测试。比如:架构组将操作Redis的库编写成静态类,如果执行测试将会影响Redis数据。令人头疼的是,基本上所有的免费框架都不支持Mock静态类。目前,我采取的方法是使用JustMock的付费功能。经验有限,希望发到博客有大神指出解决方案。
测试驱动开发——TDD
- TDD 的理念
当我们拿到需求,按照瀑布流开发的模式进行的发,应当是创建业务项目,编写业务代码,需要的话编写测试代码,测试工程师测试,然后验收发布。
而在TDD中,我们需要面对需求编写测试代码。先写测试代码,我相信很多人都会觉得很困惑,没有逻辑,没有方法,测试代码测试什么?TDD的理念是测试先行。 - TDD 的好处
- 严格根据TDD思维,遵循SOLID原则 开发能保证代码质量
- TDD 确保了代码与业务需求高度一致性
- TDD 鼓励创建更简单、针对性更强的库和API
- TDD 要落实测试单元,需要鼓励与业务方持续沟通
- TDD 有助于清除无用代码。无用代码实际上维护成本非常高
- TDD 提供了内置的回归测试。再次执行测试代码可检查修改一个方法逻辑会不会影响到其它现有功能
- TDD 阻止递归错误。每个测试都针对系统缺陷,那么,同样的错误不会再次发生
- TDD 开发应用程序的系统是开放的、可扩展的、灵活的系统。
以上都是废话,我还没完整体验过真正的TDD开发线上系统。理解测试驱动开发的理念,能让我们编写更漂亮的代码倒是真的。
- TDD 如何完成软件开发
TDD 的三个阶段:
- 红灯阶段
编写贴合需求的测试代码,尽量保证覆盖需求每个点。 - 绿灯阶段
编写适当代码,使测试通过。合理命名一个方法名,然后简短完成方法。可能一个范湖bool型的方法只写一个返回代码。 - 重构阶段
这个阶段是真正完成业务逻辑的阶段。因为我们编写的测试代码已经完整满足业务需要,所以,我们只需要根据测试代码,编写完业务代码,再通过测试即可。
完成一项工程,不要期待只走一遍流程就完成了,写代码从来没有容易的事,很多时候,我们都需要反反复复修改,不仅仅是需求更改,也为了让我们“以前”写过的代码更整洁。
我目前还是觉得,很艰难能坚持TDD模式开发,很难让你的团队的伙伴都转变思维,从测试代码开始。但不妨碍我们去体会TDD,我们带着测试的思维去写业务代码,时刻都想着,我这样设计会不会很难测试。如果我们的代码让我们很难测试,我相信他大概率也不是好的代码。
以上,我的理解。学无止境,望高人指点一二,向大佬学习。