开发测试一山容得二虎,30条有关测试的故事和事
分类:彩世界彩票注册平台官网

19. DRY在测试中没有在生产代码中要紧。单个测试文件的可读性比可维护性更重要(跳出模块复用的限制)。这是因为测试是单独被执行和阅读的,而且它们自己不是大系统的一部分。虽然在很多重复的时候创建可重用的组件更方便,但相较于产品代码,测试代码较少考虑。

17.如果一个函数或方法超过30行代码,就要考虑分解。好的最大模块大小约为500线。测试文件往往比这个更长。

加入一个企业文化和编程实践已经定型的新公司,可能会是一种令人沮丧的经历。当我加入 Ansible 团队后,我决定整理我多年以来所学并为之奋斗的软件工程实践和准则。这是一个不明确的也不够详尽的准则列表,使用它们时需要智慧和灵活性。

  1. Generators rock! 与有状态的对象相比,它们用于迭代或重复执行通常更短,更容易理解。

14. 依赖注入是一个实用的编程模式,明确你的依赖是什么和它们来自哪里。(对象,方法等以参数的形式接收它们的依赖,而不是实例化新对象本身。)这确实让 API 签名更复杂,所以这里需要权衡。如果一个方法最后为所有的依赖设置了10个参数,那这是一个不错的信号,不管为什么你的代码做得太多。关于依赖注入的权威文章是 Martin Fowler 的《控制反转容器&依赖注入模式》(《Inversion of Control Containers and the Dependency Injection Pattern》)。

10.防守地写。要总是想可能出现什么问题,无效输入会发生什么,什么可能导致失败,这有助于在错误发生前发现错误。

30. 最后一点:只关注特性改进是开发软件的一种可怕方式。如果开发者的工作不能确保最好的结果,那么不要让他们为自己的工作感到自豪。不处理技术债务会使开发变慢并最终导致产品更糟,问题更多。

  1. YAGNI:不要编写现在尚不需要,而将来可能需要的代码。现在的代码不可避免地会变成死代码或需要重写,因为未来的用例总是与设想的不同。如果把代码放在未来的用例中,在代码审查中要提出质疑。(例如,可以并且必须设计API来允许将来的用例,不过,这是另外一个问题。)

5. 快速失败。检查输入,如果遇到无意义输入或非法状态则尽早失败,最好是通过异常或错误响应使问题对调用者变得清晰。允许你的代码处理“有创意”的用例(例如,除非真的需要,否则在做输入验证的时候不要做类型检查)。

9.随着时间的推移,代码注释不可避免地成为谎言。实际上,很少有人在事情发生变化时更新评论。通过良好的命名实践和已知的编程风格,努力使代码有可读性和自我记录。

26.让我们成为工程师!让我们考虑设计、构建健壮并实现良好的系统,而不是做膨胀的有机怪物。然而编程是一种平衡。我们并不总是建造火箭。过度设计同设计不完善的代码一样,处理起来非常痛苦。Robert Martin 的作品几乎都值得一读,《架构之洁:一个工匠的软件结构和设计指南》(《Clean Architecture: A Craftsman’s Guide to Software Structure and Design》)是这个话题一个很好的资源。《设计模式》(《Design Patterns》)是每一位工程师都应该阅读的经典编程书。

12.Globals are bad。功能优于类型,对象比复杂的数据结构更好。

对于那些晦涩的代码,一定要写注释,例如偶发错误或意外情况的变通方案,或者必要的优化。解释代码的意图和及其原因,而不是解释代码在做什么。(顺便说一句,有些观点认为注释变谎言是有争议的。我仍然认为这是正确的,《程序设计实践》(《The Practice of Programming》)的作者 Kernighan 和 Pike 同意我的观点。)

软件工程规则和测试积累的最佳实践,能帮助企业显著节省时间,减少痛点。良好的测试实践既可以确保质量标准,也可以指导和塑造每个程序员的发展。

2 . 测试不需要测试。用于测试需要的基础设施、框架和库需要测试。除非你真的需要不要测试浏览器或外部库。测试你写的代码,而不是别人的代码。

  1. “这里没有发明”并不像人们所说的那么糟糕。如果我们编写代码,我们知道它的作用,知道如何维护它,可以自由地扩展和修改它。这是遵循了YAGNI的原则:我们有需要用例的特定代码,而并非通用代码,通用代码会给我们不需要的部分带来复杂性。另一方面,代码是敌人,拥有更多的代码没有好处,当引入新的依赖关系时需要考虑权衡。

13.使用 Python 内置类型及其方法将比自己编写的类型运行快(除非你用C语言编写)。如果性能是一个考虑因素,请尝试弄懂如何使用标准的内置类型,而不是自定义对象。

13.使用 Python 内置类型和方法比编写自己的类型更快(除非用C编写)。如果考虑性能,尝试解决如何使用标准内置类型而不是自定义对象。

22. 当更小、范围有限的单元测试失败的时候,可以给出更多有价值的信息,告诉你具体是什么错误。如果一个测试牵涉了半个系统来测试行为,那么它需要更多的调查以确定什么是错误的。一般来说,运行超过 0.1 秒的测试不是单元测试。没有所谓的慢单元测试。用限定范围的单元测试测试行为,你的测试行为扮演了事实上的代码规范。理想情况下如果有人想了解你的代码,他们应该能够把测试套件转换为行为的“文档”。Gary Bernhardt 的《快测,慢测》(《Fast Test, Slow Test》)是关于单元测试实践的一篇很棒的演讲。

21.正确的编写代码第一,速度第二。处理性能问题时,请务必在修复之前进行配置。瓶颈通常出乎你的意料。编写难懂的代码如果是为了速度更快,为此你进行了配置并证明这么做是值得的,那么也仅仅是速度上值得而已。编写一个测试,训练正在配置的代码,让它知道什么情况下会变得更简单,并且留在测试套件中,来防止性能下降。(通常情况下,添加计时代码总是会改变代码的性能特点,使性能变得经常差强人意。)

20.每当你看到有需要有机会就重构。编程是关于抽象的,你的抽象映射越接近问题域,代码就越容易理解和维护。随着系统的有机增长,需要改变结构以扩大它们的用例。系统越来越多的抽象和结构,如果不改变它们就成为技术性的债务。它会是更加痛苦的工作(更慢,越来越多的错误)。在特性开发估计中请考虑清除技术债务的成本。你遗留债务的时间越长,积累的利息就越高。关于重构和和测试的一本很棒的书是 Michael Feathers 的《修改代码的艺术》(《Working Effectively with Legacy Code》)。

30.最后,管理要点:持续的功能研发是开发软件的一个可怕方法。不让开发人员在工作感到骄傲, 就不会从中获得最大的利益。不解决技术债务,会拖慢开发速度,并导致更糟糕的、更多bug的产品。

  1. 面向外部的 API 是“预先设计”——同时要考虑未来的用例——真正重要的地方。改变 API 对我们和用户来说是一种痛苦,造成向后不兼容是可怕的(尽管有时无法避免的)。设计面向外部的 API 要细心,仍然要坚持“把简单的事情做简单”的原则。

16.面向外部的 API 是要“预先设计”的,它关系到未来用例。改变 API 对自己和用户来说都是一种痛苦,而创造向后兼容性是非常可怕的,尽管有时不可避免。精心设计面向外部的API,仍然坚持“简单的事情简单化”的原则。

15. 需要模拟测试的代码越多,你的代码就越糟糕。为了测试一个特定的行为,需要实例化和牵扯的代码越多,代码越糟糕。我们的目标是小型可测试的单元,以及更高级别的集成和功能测试,以测试各单元是否配合正确。

小数今天推送的这篇文章,文中的许多原则都与测试实践和理想有关,有一些还是Python特有的。正如本文作者所说,程序员的那些固执己见,强烈的意见表达和坚持,往往是激情的最好表现。

24. 共享代码所有权是我们目标;沉默的知识不是好知识。这意味着最低限度要讨论或记录设计决策和重要的实施决策。代码评审(Code Review)是开始讨论设计决策的最坏时刻,因为在代码编写后,很难彻底更改。(当然在评审时指出并修改设计错误比没有好。)

22.更小范围的单元测试在失败时会提供更有价值的信息。要判定错误,有一半的系统测试行为的测试需要依据更多的调查。一般来说,运行时间超过0.1秒的测试不是单元测试。没有所谓的慢单元测试。通过严格范围的单元测试测试行为,你的测试可以作为代码实际规范。理想情况下,如果有人想了解你的代码,应该能够将测试套件作为行为的“文档”。

编译:伯乐在线/maifans

24.共享代码所有权是目标。孤立的知识没什么好,这意味着至少要讨论、记录贯彻设计决策和实施决策。代码审查时开始讨论设计决策是最糟糕,因为在编写代码之后进行彻底的更改太难克服了。当然,在Review时指出和修改设计错误,比永远不总结不思考要好得多。

  1. 生成器很棒!它们通常比迭代或重复执行的状态对象更短更容易理解。David Beazley的《系统程序员的生成器诀窍》(《Generator Tricks for Systems Programmers》)是关于生成器一个很好的介绍。

不明确的代码确实需要注释,比如围绕一个模糊的错误或不可能的条件,或者必要的优化。

18 .不要在对象构造函数中工作,这里很难测试而且经常发生意外。不要在__init__ .py中添加代码。__init__ .py不是程序员通常期望找代码的地方,所以它是个“惊喜”。

27.间歇性地失败的测试会侵蚀测试套件的价值,以至于最终每个人都忽略测试运行的结果。修复或删除间歇性失败的测试是痛苦的,但值得努力。

21. 代码正确为第一位,速度快第二位。在处理性能问题时,在修复错误之前先要做性能剖析。通常瓶颈不是你认为的那样。如果写晦涩的代码的唯一价值就是更快而且你已经做过性能剖析并证明了,那么它实际就是值得的。编写测试定期检测你要做性能剖析的代码,这样可以很容易让你知道你什么时候测试过。测试可以留在测试套件中,以防止性能退化。(通常情况下,添加定时代码总会改变代码的性能特性,使性能工作成为令人沮丧的任务之一。)

20.当看到需要并有机会时进行重构。编程是关于抽象的,抽象映射越接近问题域,代码就越容易理解和维护。随着系统有机地增长,需要为扩展用例而改变结构。系统超出抽象和结构,而不改变它们成为技术债务,这会更痛苦,更缓慢,更多bug。包括重构成本,包括对功能的预估。你把债务拖得越久,它积累的利息就越高。Michael Feathers 撰写了一本关于重构和测试的书籍,其中着重介绍了遗留代码。

28. 一般来说,特别是在测试中,在需要等待一个特定的变化时候不要采用休眠随机时间的方式。Voodoo 的 sleeps 很难理解而且使你的测试套件变慢。

3.第三次编写相同代码时,是将其抽取到通用帮助器(并为其编写测试)的正确时机。测试中的辅助功能不需要测试; 当把它们分解出来并进行重用时,才需要测试。到第三次编写类似的代码时,会清楚地知道正在解决什么样的问题。

我对测试充满热情,因为我相信良好的测试实践既能确保满足最低质量标准(可悲的是许多软件产品做不到),并能指导和塑造开发本身。本文提到的这些准则,很多是与测试实践和理念相关的。其中一些准则针对 Python 的,但大多数不是。(对于 Python 开发者,PEP 8 应该是编程风格和指南的首先。)

11.如果逻辑无状态且无副作用,则易于进行单元测试。将逻辑分解成独立的函数,而不是混合成有状态和副作用的代码。将有状态和带副作用的代码分离成更小的函数,可以更容易地模拟和单元测试。副作用确实需要测试,测试一次并在其他地方进行模拟,是比较好的做法。

27. 间歇失败的测试会侵蚀测试套件的价值,以至于最终每个人都忽略测试运行结果,因为总有一些失败的事情。修复或删除间歇性失败测试是痛苦的,但这些努力是值得的。

5.快速失败。尽可能早地检查输入,并在无意义的输入或无效状态上失败,使用异常或错误响应,来确定问题。允许代码“创新”,也就是说,通常情况下,不要对输入验证进行类型检查。

  1. 全局变量不好。函数优于类型。对象可能比复杂的数据结构更好。

对于一些复杂的场景,比如一些特定复杂状态下,测试行为找到一个难以理解的错误。编写测试确实有助于解决这个问题,因为它会迫使你在编写代码之前,考虑清楚代码的行为以及如何测试。测试首先鼓励更小,更模块化的代码单元。

开发和测试的最佳实践

7.对于单元测试(包括测试基础结构测试),应该测试所有的代码路径。100%的覆盖率是一个很好的起点。你不能涵盖所有可能的排列/组合状态。在有很好的理由时,代码路径才能被测试。缺少时间不是一个好的理由,这往往导致最终花费更多时间。好的理由包括:真正无法测试,在实践中不可能实现,或者在测试中其他地方被覆盖。没有测试的代码要承担责任。衡量覆盖率,并拒绝降低覆盖率的百分比是朝正确方向前进的一种方法。

23. ”非我所创“不像人们说的那么坏。如果代码是我们写的,那么我们知道它是什么,我们知道如何维护它,在我们可以在适当的时候自由地扩展和修改它。这遵循了 YAGNI 原则:我们用那些适合我们需要用例的特定代码,而不用我们不需要的可以做复杂事情的通用代码。另一方面,代码是敌人,拥有必要的代码比拥有更多的代码更好。引入新的依赖关系时要权衡。

原文作者:Michael Foord
原文链接:
https://opensource.com/article/17/5/30-best-practices-software-development-and-testing

这些软件开发和测试的最佳实践,可以帮你节省时间和避免问题。

28.一般来说,尤其是在测试中,等待一个具体的改变,而不是任意时间内sleeping。Voodoo sleeps 很难理解,而且会放慢测试套件。

29. 至少让你的测试失败一次。故意加入一个错误,并确保它失败,或在测试的行为不完整的情况下运行测试。否则你不知道你真的在测试什么。瞎写的测试实际上不能测试任何东西或它很可能永远不会失败。

  1. 单元测试是对行为单元的测试,而不是对实现单元。改变实现,而不是改变行为或被迫改变任何测试,当然这点并不是总能实现。在可能的情况下,将测试对象视为黑盒子,通过公共 API 进行测试,而无需调用私有方法或修改状态。

在一些复杂的情况可能做不到,如在特定的复杂状态下测试行为,以找到一个偶发的错误。这一点对于写测试非常有帮助,因为它迫使你在写测试代码之前思考你代码的行为以及你将如何测试它。测试首先鼓励更小,更模块化的代码单元,这通常意味着好代码。关于“测试优先”方法有一本很好的入门参考书,就是 Kent Beck 写的《测试驱动开发》(《Test Driven Development by Example》)

18.不要在难以测试的对象构造函数中工作。不要把代码放在init.py中。程序员不希望在init.py找到代码。

彩世界彩票注册平台官网 1

8.代码是敌人:可能出错,需要维护。少写代码。删除代码。不要编写你不需要的代码。

6.单元测试测的是行为单元,而不是实现单元。我们的目标是在改动实现的情况下不改动行为,也不必更新测试,尽管这个目标不总是能实现。因此在可能的情况下将测试对象视为黑盒,通过公共 API 测试,而不调用私有方法或玩弄状态位。

  1. 依赖注入是一种有用的编程模式,可以清楚了解依赖关系。(让对象,方法等接收依赖关系作为参数,而不是自己实例化新的对象。)这是一种交换,使API签名更加复杂。如果完成依赖项需要使用10个参数,说明代码太多了。

  2. 越需要模拟测试代码,它就会越糟糕。需要实例化和放置的代码越多,用来测试特定的行为,代码就越糟糕。测试的目标是小型可测试单元,和更高级别的集成和功能测试,来测试这些单元是否正确地协作。

  1. 对于单元测试(包括测试基础设施测试),所有代码路径都应该被测到。100% 覆盖是一个好的开始。你不能覆盖所有可能状态的排列/组合,因此这个问题需要考虑。只有当有很好理由的情况下才允许有代码路径未经测试。没有时间不是一个好理由,最终会花费更多的时间。可能的好理由包括:真正的不可测(以任何有意义的方式),现实中不可能发生,或被其它测试覆盖。没有测试的代码是一种债。测量覆盖率和拒绝减少覆盖率 PR 是确保你在正确的方向演进的一种方式。

注解代码也是如此。如果一个注释代码块进入发行版,它就不应该存在。如果是可以恢复的代码,创建一个ticket,并引用代码删除的提交散列。YAGNI 是敏捷编程的核心元素。Kent Beck提供的极限编程解释(Extreme Programming Explained)就是最好的参考。

感谢 Ansible 团队,尤其是 Wayne Witzel,为改善这个列表中的准则而提出的意见和建议。

4.涉及到API设计:简单的事情简单化; 复杂的事情可能如果可能也简单化。首先设计一个简单的情况,如果可能,最好使用零配置或参数化。为更复杂和更灵活的用例添加选项或其他API方法。

  1. 现在来谈谈 API 设计(面向外部的对象API):把简单的事情做简单了,复杂的事情自然成为可能。首先设计简单的用例,如果有可能最好是零配置或参数化。为更复杂和灵活的用例增加选项或额外的 API 方法。
  1. DRY(Don’t Repeat Yourself不要重复自己)在测试中比在生产中重要得多。单个测试文件的可读性比可维护性更重要(突破可重用的块)。这是因为测试是单独执行和读取的,而不是作为大系统的一部分。过多的重复意味着可重用的组件可以方便地创建,但是与生产相比,测试的重要性低得多。

17.如果函数或方法超过 30 行代码,考虑分解它。一个良好的模块最大约 500 行。测试文件往往比这个要大。

2.测试本身不需要测试。用于测试的基础架构,框架和库需要测试。除非确实需要,通常不要测试浏览器或外部库。测试你写的代码,而并非其他人的。

10. 防守思维。总是考虑什么会出错,无效的输入会引发什么,什么可能会失败,这将有助于你在许多错误发生之前发现他们。

29.至少要看到你的测试失败过一次。将一个蓄意的 bug 放入让它失败,或在测试行为完成之前运行测试。否则,你不知道你真的在测试。偶尔写写测试代码实际并不测试任何东西,或写永远不会失败的测试,都是很容易的。

8. 代码是敌人:它可能出错,并且需要维护。少写代码,删除代码,不要写你不需要的代码。

26.让我们成为工程师!设计、建立强大和良好实施的系统,而不是增加有机怪物。编程是一个平衡的行为,我们并不总是建造火箭飞船,过度设计(onion architecture洋葱架构)与设计不足的代码同样令人痛苦。罗伯特•马丁(Robert Martin)所做的几乎任何事情都值得一读,“ 干净架构:软件结构和设计指南”( Clean Architecture: A Craftsman’s Guide to Software Structure and Design )是这方面的好资源。设计模式( Design Patterns)是每个工程师应该阅读的经典编程书籍。

  1. YAGNI 原则:“You Aint Gonna Need It”。不要写你认为将来可能需要但现在不需要的代码。这是为假想的未来用例编码,这些代码将不可避免地变成死代码,或需要重写,因为未来结果总是与想象的稍有不同。

这条原则也适用于被注释掉的代码;如果一个被注释掉代码块即将进入一个发布版本,那么它就不应该存在。如果代码可能要还原,请为代码删除创建一个问题单并引用提交对象的哈希字符串。YAGNI 原则是敏捷编程的核心要素,这个话题最好的参考书是 Kent Beck 写的《解析极限编程》(《Extreme Programming Explained》)。

11.无状态和无副作用的单元测试,其逻辑应简单。将逻辑分解成单独的函数,而不是将逻辑混合到有状态和充满副作用代码中。将有状态代码和有副作用代码,分为较小的更容易模拟的函数和无副作用地单元测试。(测试的开销越小意味着更快的测试)副作用确实需要测试,但是测试一次然后处处模拟它们通常是一个好的模式。

3.当第三次编写相同的代码时,也是将其提取成通用的辅助函数的正确时机。测试中的辅助函数不需要测试;但当你将它们剔除出去然后再重用它们时,它们需要测试。到你第三次编写类似代码的时候,你通常会清楚地认识到你正在解决的通用问题的模型是什么。

如果你写代码用于将来的用例,我将在代码评审中对其质疑。(你可能而且必须设计 API,并确保未来的用例可用,但这是不同的问题。)

9. 随着时间的推移,代码注释不可避免地成为谎言。在现实中,很少有人在事情变化的时候更新注释。通过良好的命名法和已知的编程风格,努力使你的代码可读和自文档化。

本文由彩世界注册首页发布于彩世界彩票注册平台官网,转载请注明出处:开发测试一山容得二虎,30条有关测试的故事和事

上一篇:中南传播媒介怎么转型教育行当彩世界彩票注册 下一篇:没有了
猜你喜欢
热门排行
精彩图文