你可能面临过下述一个或者多个痛点、问题或者导致交付失败的原因:
测试驱动开发可以简化重构工作、帮助创建更好的设计以及降低耦合程度。
当要掌握TDD是一个漫长的过程,需要很长的时间和大量的实践。
如果新编写的测试未通过,说明实现不正确,需要修正。
如果其他测试未通过,说明我们破坏了某种功能,必须撤销所有修改。
花足够的时间修复代码,让所有测试都通过。
如果不能在几分钟内完成修复,最佳的选择是撤销所做的修改。毕竟修改前一切都是正常的,刚编写的实现显然是带有破坏性的,错误的。所以为何不会到原来的地方,重新考虑正确的实现测试的方式呢?这样我们只是在错误的实现上浪费了几分钟。
你可以使用任务你喜欢的方式编写代码,但要快。一旦进入绿灯状态,我们就知道存在一个由测试构成的安全网,基于这个安全网重构代码。重构结束后,所有测试应当还是能通过的。
如果在重构完成后,有测试未通过,就说明重构破坏了既有功能,应该撤销所做的修改。在重构阶段,我们不修改任何功能,也不引入新的测试,而只是改进代码,并不断运行所有测试,确保没有破坏功能。
重构结束后,在重复整个过程。这个一个无限循环,每次循环都是一个极短的周期。
不要试图让新编写的测试的实现完美无缺,而应只编写足以让这个测试通过的代码就可以了
黑盒测试(也叫功能测试)将首测软件视为一个黑盒,无需知道其内部构造。这种测试时通过软件界面进行的,旨在确认它们能想预期的那样工作。只要界面的功能未发生变化,测试就应通过,即使内部构造发生变化。这种测试方法提供了外部观察受测软件的结果。
自动化黑盒测试依赖于某种形式的自动化,如行为驱动开发(BDD)
白盒测试查看受测软件的内部,并将由此获得的知识用于测试过程。例如,如果在特定条件下应引发异常,可能需要在测试中重现这种条件。白盒测试要求测试人员了解系统的内部结构,同时具备编程技能;它提供从内部观察受测软件的结果。
需求(规范和用户故事)是在实现需求的代码之前编写的,因此它们定义了代码。
对于测试来说,如果它们实在代码之后编写的,那么是代码(以及其实现的功能)定义了测试。由既有应用程序定义的测试有失偏颇,倾向于确认代码的功能,而不是检查客户的需求是否得到了满足,或者说代码的行为是否符合预期.
使用模拟对象(mock
)可以规避外部依赖(数据库、Web服务器、外部API等)。
通过模拟外部依赖,可大幅度提高测试测试,但想要轻松使用模拟对象就必须分离关注点以优化代码
TDD
另一个很有用的方面是文档。要搞清楚代码时干什么的,通过查看测试了解比查看实现了解要容易的多。
传统软件文档存在的主要问题是,它们通常不是最新的。一部分代码发生变化后,文档便不再反应实际情况。几乎任何类型的文档都是如此,需求和测试用例受到的影响最大。
需要为代码编写文档通常意味着代码本身写得不好。另外,不管你如何努力,文档都必然会过期。
可通过阅读代码来了解系统细节,其他类型的文档提供快速指南和概述。非代码文档应回答诸如“系统的总体目标是什么” “系统使用了那些技术”等问题,而其他方面,代码就是“圣经”。
实现代码提供了所需要的所有细节,而测试代码描述了产品代码背后的意图。
测试就是可执行的文档,而TDD是创建和维护这种文档的最常见的方式。
在编写代码前编写测试,并且测试代码覆盖率很高的情况下,我们完全可以相信应用程序将会像预期的那样工作。如果发现bug,我们也可以轻松找出它们,只需要查看未被测试覆盖的代码即可。
测试本身可能没有涵盖某些情况。这种情况下,应对措施是编写额外的测试。
测试代码覆盖率很高的情况下,与逐行调试直到找到bug相比,通过测试找到导致bug的原因要快很多。