资深程序员:软件开发测试的25个忠告!

时间:2023-02-12 08:44:59
当我加入Ansible团队之后,我决定写下多年来所学到的软件工程实践和原理方面的经验。我的激情是测试,因为我相信良好的测试既可以确保最低质量标准(可惜很多软件产品都缺乏这一点),也可以指导和塑造开发过程本身。以下许多建议与测试有关,其中一些原则甚至特定于Python,但绝大多数不是。(对于Python程序员,PEP 8应该是编程风格和指南的第一站。) 资深程序员:软件开发测试的25个忠告! 1、不要编写你认为以后可能需要但目前不需要的代码。这是对未来想象的用例的编码,并且这种代码一定会成为死码或需要重写,因为未来的用例总是与程序员的想象略有不同。 注释代码也是如此,如果一段注释的代码正在进行发布,它不应该存在。YAGNI是编程的核心要素,最佳参考资料是极限编程解析(Extreme Programming Explained)。 2、不进行多余的测试。基础设施,框架和库是需要测试的,不要测试浏览器或外部库,除非你真的需要。测试你自己编写的代码,而不是其他人写的代码。 3、多次重复出现的代码不需要测试。辅助功能不需要测试,当你把它们分开并重新使用时,需要测试。如果反复编写类似代码多次时,您通常会很清楚正在解决的问题。 资深程序员:软件开发测试的25个忠告! 4、关于API设计(外部面向对象API):简单的事情尽量简单完成,复杂的事情尽力优化。首先为简单案例设计,如果可能的话,优选为零配置或参数化。Addoptions或附加的API方法,用于更复杂和更灵活的用例(根据需要)。 5、尽早检查无意义的输入或无效状态,最好是异常或错误响应,这将使程序员很清楚问题的确切信息。(除非真的需要,否则不要进行输入验证类型的检查)。 6、在可能的情况下,将测试对象视为黑盒子,通过公共API进行测试,这就不需要调用私有方法或修改状态。 对于一些复杂的场景,编写测试真的是有帮助的,因为这迫使程序员考虑代码的行为以及在编写代码之后如何进行测试。测试首先鼓励更小、更模块化的代码单元,这通常意味着更好的代码。 7、对于单元测试(包括基础架构测试),应测试所有代码路径。 100%的覆盖是一个良好的开端。除非你无法覆盖所有可能的排列/组合的状态,只有一个非常好的理由才能使代码路径不全部经过测试,以时间为借口早晚会浪费更多时间。 8、代码是敌人:可能出错,需要维护。尽量有更少的代码实现必需的功能,删除不必要的代码。 9、努力通过良好的命名规范和已知的编程风格使代码可读和形成自我记录。通常随着时间的推移,很多程序员都不认识自己写的代码了。 10、代码注释——对一些无法明确的代码,请尽早提供注释,说明为什么要这么写,有无其他方法等。 11、编码过程中务必想想可能出现的问题,无效输入会发生什么,哪些情况会导致失败,这将有助于程序员在发生错误之前捕获更多错误。 12、简单的逻辑易进行单元测试,将逻辑分解为单独的函数,而不是将逻辑混合为有状态和有副作用填充代码。(测试的开销越少意味着测试更快)。 13、使用对象可能比使用复杂的数据结构更好。使用Python的内置类型及其方法将比编写自己的类型更快(除非您在C中编写)。如果考虑性能,请尝试了解如何使用标准内置类型而不是自定义对象。 14、依赖注入是一个有用的编码模式,用于程序员搞清楚依赖关系以及它们来自哪里(有对象,方法等作为参数接收它们的依赖关系,而不是实例化新对象本身)。关于依赖注入的文章可参考Martin Fowler的“Inversion of Control Containers and the Dependency Injection Pattern”。 15、代码越多,代码越差。程序员的目标应该是小型的可测试单元,以及更高级的集成和功能测试,以测试单元是否正确合作。 资深程序员:软件开发测试的25个忠告! 16、设计API时应该考虑到以后可能会遇到的更改,并考虑到未来的用例——真的很重要。改变API对程序员和用户而言都是一种痛苦,并且创建向后的不兼容性是可怕的(尽管有时不可避免)。 17、如果函数或方法超过30行代码,请考虑将其分解。最大模块尺寸为500行,测试文件往往比这更长。 18、不要在对象构造函数中工作,这很难测试。不要将代码放在__init__.py中(除了用于命名空间的导入)。 __init__.py不是程序员通常期望找到代码的地方。 19、在测试中,单个测试文件的可读性比可维护性更重要(打破可重用的块)。这是因为测试被单独执行和读取,而不是自己成为较大系统的一部分,显然过多的重复意味着可以为了方便而创建可重复使用的组件,这不仅仅是生产问题。 20、尽可能使用重构。编程是抽象的,越接近问题域,代码越容易理解和维护。随着系统的发展,用例的结构需要改变和扩展。一本关于重构和测试的书是Michael Feathers的Working Effectively with Legacy Code。 21、在处理性能问题时,请务必在修复之前进行配置。如果你已经剖析并证明代码实际上是值得的,编写一个测试随时对代码进行分析,并且保留在测试套件中以防止性能回归。(添加时间码总是会改变代码的性能特征,使性能成为更令人沮丧的任务之一)。 22、更小,更严格的单位测试在失败时提供更有价值的信息。通常,运行超过0.1秒的测试不是单元测试。单元测试可以提供更具体的错误信息,关于单元测试实践一本不错的书是Gary Bernhardt的Fast Test, Slow Test。 23、遵循YAGNI原则:编写我们需要的特定代码,而不是不需要的、复杂性的通用代码。 24、共享代码所有权是目标。不分享或许就发现不了更好的编写方式,比如分享出来,大家集思广益。 25、最后,可以告诉产品经理或开发商,一味地增加功能并不是好事,确保核心功能的高效率工作就可以了。