使用 JUnit、AssertJ 和 Mockito 编写单元测试和实践 TDD (二)为什么要写单元测试
上一章讲到“什么是单元测试”,这一章我们讲讲“为什么要写单元测试?”
听到这个问题,我的直接回答就是:
“为什么不写单元测试?”
不过为了说服那些怀疑论者,我还是罗列一下单元测试的好处。从生理到心理,从做事到做人。:)
保证代码正确性
这个不用多说,保证代码正确性是单元测试的题中之义。
保证代码在边缘状态和异常条件下的正确性
全面的单元测试覆盖不仅保证了代码在一切正常的情况下的正确性,还会保证代码在各种特殊条件下的正确性。在上一章列举的银行账户的取款方法中,单元测试除了保证在账户状态正常且余额足够的情况下取款行为的正确性,还保证了在账户冻结、余额不足、取款金额不合法等等异常情况下的正确性。如果没有单元测试覆盖这些可能性,代码很可能在运行时出错,导致系统故障,严重时甚至会导致业务损失。
通过回归测试保证代码在未来的正确性
在软件开发过程中,我们会经常修改和重构代码。由于有预先写好的单元测试的保护,我们可以在修改代码后重新运行原来的单元测试(即回归测试)。如果测试仍然通过,我们就知道这次修改没有破坏任何东西;如果测试失败,我们就知道这次修改引入了bug,可以及时定位和改正它。除了修改代码之外,当我们更换了依赖库,或升级了依赖库的版本时也可能因为兼容性问题导致bug。在这种情况下单元测试也可以及时发现和定位这些故障。我自己的一个项目在将hibernate版本升级时,就是单元测试替我发现和定位了bug。
单元测试帮助及时发现和定位Bug
软件总是充满各种不同严重级别的bug。改正bug很容易,最大的问题就是不知道有没有bug,第二大问题就是不知道bug的确切位置。假设你上线了一个在线金融类项目,但是里面潜藏着一个bug:客户取款时没有扣减他的账户余额。这样的项目上线后一两星期都没有发现这个bug,那么资金的损失会是个惊人的数字!单元测试不但可以及时发现bug,还能准确定位bug——哪个单元测试失败了,bug就在这个单元测试所测试的工作单元里面!要测试,不要调试!!!
单元测试作为代码的文档,为他人和未来的自己指路
单元测试作为代码的第一个客户,本身起着文档的作用,尤其是当你根据测试意图给每个测试方法取了个合适的名字的时候(例如将测试余额不足的单元测试方法命名为shouldFailWhenBalanceNotEnough())。单元测试作为代码比文字版的文档更加直观。另外,文档常常会过时(很多人在修改了代码之后忘记修改文档),单元测试跟紧产品代码,永不过时。
可测试性的要求会防止程序员写出糟糕的代码
如果要求全面的单元测试覆盖,你就必须保证你写的代码都是可测试的。在可测试性的要求下,你就不太可能写出一个上千行代码的方法,里面包含了几十个if...else...,甚至一层套一层的条件分支和循环语句——因为这样复杂的方法根本不可能进行测试。可测试性的强迫你写简单的代码。简单的代码就是好代码。
减轻心理负担,自信地编码
没有单元测试覆盖,我们对自己的提交的代码很难有充分的信心。我们很多人是战战兢兢地提交了代码,然后在内心祈祷它“千万别出错”。很多人睡不安稳,担心因为代码中的bug而在半夜听到领导或客户在电话里的咆哮。我们很大一部分时间花在寻找bug和调试代码上面,而不是用于编写有用的功能。这些都是由于前期缺乏单元测试所致。
树立专业形象,获得同事、上司、客户的认可与赏识
如果我们能够通过编写单元测试,保证了代码方方面面的正确性和可靠性。那么在同事、上司和同事的眼中,我们就是专业的、可靠的人。与由于代码出错而挨批评受鄙视相比,我们会对自我形象感觉满意,幸福感也会增强。我觉得这才是编写单元测试最大的好处。
单元测试是一次投资,终身受益。是个一本万利的生意。很难想象一个心智正常的程序员会不写单元测试。
下一章将讲讲“单元测试在整个测试体系中的位置”!
版权声明: 本文为 InfoQ 作者【编程道与术】的原创文章。
原文链接:【http://xie.infoq.cn/article/b91d4865525fad3f1bf218195】。文章转载请联系作者。
评论