在许多程序员眼中,单元测试似乎是可有可无的,觉得这应该是测试人员的工作。实际上,测试代码和生成代码同样重要。我们不但需要测试代码,而且需要的是整洁的测试代码。
测试为什么要整洁
我们对待测试代码需要像对待生产代码一样,写之前需要进行严谨的思考、详细的设计。这里分享一下我自己的学习编程的一些经历。
没有单元测试
刚毕业的时候,我的代码可以说是年少轻狂,总是对自己充满自信。根本就不写单元测试,写完之后自测也是随意的点两下就算自测通过了。代码提交测试后,恐怖的事情就出现了,铺天盖地的bug向我袭来。每天工作有一半以上的时间是在和测试同事沟通,其余的时间是在改bug。本来1天的工作可能需要3天才能完成。当我意识到这样做完全是费力不讨好的时候,我决心每次写完代码之后,要写一段单元测试,保证单元测试通过后再提交。
随意的单元测试
在开始写单元测试之后,我的工作效率提高了很多,下班都比原来早了。感觉写单元测试是一个无比正确的决定。随着项目的进行,中间处理过几次紧急的bug fix,当时就没有顾上去写单元测试。然而,当我又一次完成一个新的feature的时候,像往常一样开始跑单元测试,结果是:Failed!就是因为之前的改动导致的。由于手里还有其他比较紧急的工作,单元测试又被放下了。就这样,我又回到了没有单元测试的工作状态。
现在的我已经不像当初那样盲目的自信了,没有单元测试的代码让我感到恐慌。
决心重构单元测试
曾经有一段可用的单元测试放在我面前,但我没有珍惜,直到失去才追悔莫及。这次我决心重建单元测试,不但要重建,还要写一段好的单元测试。吸取上次的教训,要使我的单元测试可扩展,可维护。把一些公共的方法抽取出来,将不同概念的测试进行拆分。做到“每个概念一个测试”,测试中需要使用断言判断是否成功,而不是人为查看日志。每个测试都要包含构造-操作-检验三个环节,这三个环节要定义清楚。
这样一来,我就有了一套整洁的单元测试,后来修改代码后,单元测试可以方便的进行扩展和复用,工作效率再次提升。
整洁测试的规则
整洁测试需要遵循F.I.R.S.T规则。什么是F.I.R.S.T规则呢?
快速(Fast)
测试应该足够快,如果测试一次需要等待很长时间,没有人愿意频繁的运行测试,也就没办法快速发现问题。久而久之,我们又会失去测试……
独立(Independent)
测试之间应该相互独立,一个测试的失败不应该影响其他的测试,否则就会导致每次测试出现一大堆问题,我们每次只能解决最上级的测试暴露出来的问题,下级测试需要再次测试才行。这就会大大降低工作效率。
可重复(Repeatable)
测试应该在各种环境中可以重复执行,不论是你的本地环境,测试环境还是生产环境。测试都应该能够跑通。这样才能保证线上的质量,测试也才有意义。
自足验证(Self-Validating)
测试应该有布尔值输出(最好使用断言),我们不应该通过查看日志来判断测试是否通过,更不应该通过人为比较两个文本是否相同来判断测试是否通过。这样不但失去了测试的准确性,也浪费了我们自己的时间。
及时(Timely)
测试应该及时编写,在设计生产代码的同时就应该将测试一并设计好,不然的话,当你写好生产代码,也许会因为某些代码难以测试而放弃。
结语
总结一下今天讨论的内容,我们需要整洁的单元测试,它的地位与生产代码一样,需要我们认真设计。设计测试的时候需要遵循F.I.R.S.T原则。