Skip to content

Latest commit

 

History

History
460 lines (255 loc) · 36.3 KB

File metadata and controls

460 lines (255 loc) · 36.3 KB

九、新系统和旧系统的良好测试习惯

在本章中,我们将介绍:

  • 有总比没有好
  • 覆盖率不是一切
  • 愿意投资测试夹具
  • 如果你不相信测试的价值,你的团队也不会相信
  • 收获指标
  • 在自动测试中捕获错误
  • 从并发中分离算法
  • 当测试套件运行时间过长时暂停重构
  • 充分利用你的信心
  • 愿意放弃一整天的改变
  • 与其拍摄 100%的覆盖率,不如尝试稳定增长
  • 随机破坏你的应用程序可以产生更好的代码

导言

我希望你喜欢这本书的前几章。到目前为止,我们已经探索了许多自动化测试领域:

  • 单元测试
  • 鼻子测试
  • 博士测试
  • 行为驱动开发
  • 验收测试
  • 连续积分
  • 烟度和负荷试验

在本章中,我们将做一些不同的事情。我不想为各种提示和技巧提供大量的代码示例,而是想与大家分享我在软件工程师职业生涯中学到的一些想法。

本书之前的所有方法都有关于如何编写代码、运行代码和查看结果的非常详细的步骤。希望你能够接受这些想法,扩展和即兴发挥,并最终将它们应用到你自己的问题上。

在本章中,让我们探讨测试背后的一些更大的想法,以及它们如何增强我们开发质量体系的能力。

有总比没有好

不要被完全隔离的纯度所困扰,也不要担心晦涩难懂的测试方法。首先,开始测试。

怎么做。。。

您刚刚收到一个应用程序,该应用程序是由其他人开发的,不再与您的公司合作。你以前去过那里吗?我们都有。可能有好几次。我们能预测一些常见症状吗?

  • 很少(如果有)自动测试
  • 小文件
  • 注释掉的代码块
  • 要么代码中没有注释,要么注释是很久以前写的,不再正确

有趣的是:我们并不知道所有这些问题。我们基本上被告知在何处查看源代码树,并开始破解。例如,只有当我们遇到问题并查找文档时,我们才能发现存在(或不存在)什么。

也许我没有抓住你在列表中遇到的每一件事,但我敢打赌我找到了一个公平的数字。我不想听起来像一个愤愤不平的软件开发人员,因为我不是。不是每个项目都是这样的。但我相信我们都曾有过这样或那样的经历。那我们该怎么办?我们开始测试。

但问题在于细节。我们写单元测试吗?线程测试或集成测试怎么样?你知道吗?我们编写什么类型的测试并不重要。事实上,我们是否使用正确的名称并不重要。

当只有你和代码坐在一个隔间里时,术语并不重要。写测试才是最重要的。如果你能挑选出一小部分代码并编写一个测试,那么就去做吧!但是,如果你捡到一段杂乱无章的意大利面代码,但它并没有很好地隔离单元,那该怎么办呢?

考虑一个系统,其中可以得到的最小单位是解析电子文件的模块,然后将解析结果存储在数据库中。解析的结果不会通过 API 返回。它们只是静静地,神秘地在数据库中结束。我们如何实现自动化?

  1. 编写一个测试,首先清空与应用程序相关的所有表。
  2. 找到其中一个拥有这些文件的用户并获取其副本。
  3. 向调用顶级 API 以接收文件的测试添加代码。
  4. 添加更多代码,从数据库中提取数据并检查结果。(您可能需要抓取该用户以确保其正常工作。)

恭喜你,你刚刚写了一个自动测试!它可能不符合单元测试的要求。事实上,你可能觉得它有点难看。那又怎样?也许运行需要五分钟,但这不比根本不测试好吗?

它是如何工作的。。。

因为数据库是我们可以断言结果的地方,所以在每次运行测试之前,我们需要有一个清理过的版本。如果其他开发人员正在使用一些相同的表,那么这肯定需要协调。我们可能需要分配给我们自己的模式,以便可以随意清空表。

这些模块可能缺乏内聚性和紧密耦合。虽然我们可以尝试找出代码不好的原因,但这并不能推进我们构建自动化测试的事业。

相反,我们必须认识到,如果我们试图立即进入单元级测试,我们将不得不重构模块以支持我们。由于安全网很少或没有,风险极高,我们可以感觉到!如果我们试图坚持教科书式的单元测试,那么我们可能会放弃,认为自动化测试是不可能的。

因此,我们必须迈出第一步,编写昂贵的端到端自动化测试,以构建链中的第一个链接。该测试可能需要很长时间才能运行,而且我们所能断言的内容也不是很全面。但这只是一个开始。这才是最重要的。希望在编写更多类似这样的测试方面取得稳步进展之后,我们能够建立足够的安全网,回去重构代码。

那不可能是一切!

“只写测试”听起来有点太简单了吗?这个概念很简单。这项工作将是艰巨的。很难。

您将被迫浏览大量的 API,并了解它们是如何工作的。你猜怎么着?你可能不会得到很多中间结果去断言。理解 API 只是为了跟踪数据的传输方向。

当我将我们的情况描述为“神秘地出现在数据库中”时,我指的是,您的 API 可能没有设计很多旨在实现可测试性的返回值。

只是不要让任何人告诉你,你在浪费时间构建一个长期运行的测试用例。一个自动测试套件需要一个小时才能运行,并且每天至少运行一次,这可能比手动点击屏幕更能增强信心。有总比没有好。

另见

  • 充分利用你的信心

覆盖范围并不是一切

您已经了解了如何运行覆盖率报告。但不要认为覆盖率越高,情况就越好。以覆盖率的名义牺牲测试质量会导致失败。

怎么做。。。

覆盖率报告提供了良好的反馈。他们告诉我们什么是锻炼,什么不是。但仅仅因为执行了一行代码并不意味着它正在做它应该做的一切。

你有没有想过在休息室里吹嘘一下覆盖率?对良好的覆盖率感到自豪并不是没有道理的,但当它导致使用这些统计数据来比较不同的项目时,我们正在进入一个危险的领域。

它是如何工作的。。。

覆盖率报告是在运行它们所针对的代码的上下文中读取的。这些报告向我们展示了哪些被覆盖,哪些没有,但这并不是事情停止的地方。相反,这是他们开始的地方。我们需要查看所涵盖的内容,并分析测试如何很好地运行系统。

很明显,0%的模块覆盖率表明我们还有工作要做。但当我们有 70%的覆盖率时,这意味着什么呢?我们是否需要对其他 30%的测试进行编码?当然可以!但对于如何实现这一点,有两种不同的思想流派。一对一错:

  • 第一种方法是编写专门针对未覆盖零件的新测试,同时尽量避免与原来的 70%重叠。冗余的是,测试另一个测试中已经包含的代码是对资源的低效使用。
  • 第二种方法是编写新的测试,以便它们针对代码预期要处理但我们尚未解决的场景。未涵盖的内容应该给我们一个提示,说明哪些场景尚未测试。

正确的方法是第二种。好吧,我承认我是以领先的方式写的。但关键是,很容易查看未命中的内容,并编写一个测试,以尽可能快地缩小差距。

还有更多。。。

Python 为我们提供了令人难以置信的能力,可以使用 monkey 补丁、注入替代方法,以及使用其他技巧来运行未覆盖的代码。但这听起来不是有点可疑吗?以下是我们为自己设定的一些风险:

  • 新的测试如果不是基于合理的场景,可能会更加脆弱。
  • 对我们的算法进行重大更改可能需要我们完全重写这些测试。
  • 是否编写过基于模拟的测试?可以模拟不存在的目标系统,最终只测试模拟。
  • 尽管我们的一些(甚至大部分)测试可能具有良好的质量,但低质量的测试将使我们的整个测试套件成为低质量的。

如果我们做了干扰行计数机制的事情,覆盖工具可能不会让我们“逃脱”这些策略。但是覆盖工具是否统计代码不应该成为我们决定测试质量的标准。

相反,我们需要查看我们的测试,看看它们是否在尝试使用我们应该处理的实际用例。当我们只是在寻找提高覆盖率的方法时,我们就不再考虑我们的代码应该如何运行,这是不好的。

我们不应该增加覆盖率吗?

我们应该通过改进测试、覆盖更多场景以及删除不再支持的代码来增加覆盖率。这些都使我们的整体质量更高。

为了覆盖率而增加覆盖率不利于提高我们系统的质量。

但我想吹嘘一下我的系统覆盖范围!

我认为庆祝好的报道是可以的。与您的经理共享覆盖率报告是可以的。但不要让它吞噬你。

如果你开始每周发布报道,仔细检查你的动机。如果你的经理也要求发帖,情况也是如此。

如果您发现自己正在将您的系统的覆盖率与另一个系统进行比较,请注意!除非您熟悉这两个系统的代码,并且真正了解报告的底线之外的内容,否则您可能正在进入风险领域。您可能会进入错误的竞争,这可能会驱使您的团队编写脆弱的测试。

愿意投资测试夹具

花时间在一些测试夹具上。一开始你可能不会编写很多测试,但这项投资会有回报的。

怎么做。。。

当我们开始构建一个新的绿地项目时,编写面向测试的模块就容易多了。但是在处理遗留系统时,构建一个工作的测试夹具可能需要更多的时间。这可能很难通过,但这是一项有价值的投资。

例如,在中,我们讨论了一个扫描电子文件并将解析结果放入数据库表的系统。我们的测试夹具需要哪些步骤?

  • 清除相应表的设置步骤
  • 很可能,我们需要使用代码或脚本来创建新的数据库模式,以避免与其他开发人员发生冲突
  • 可能需要将文件存放在某个位置,以便解析器能够找到它

这些都是构建工作测试用例需要时间的步骤。更复杂的遗留系统可能需要更多步骤来准备测试运行。

它是如何工作的。。。

所有这些都会让人感到害怕,可能会迫使我们放弃自动化测试,继续点击屏幕进行验证。但是花时间对这个装置进行编码将开始有回报,因为我们编写了更多使用我们装置的测试用例。

您是否曾经构建过测试夹具,并且在某些情况下必须对其进行更改?在使用我们的夹具开发了足够多的测试用例之后,我们可能会遇到另一个需要测试的用例,它超出了我们的夹具的限制。因为我们现在已经熟悉了它,所以创建另一个装置可能更容易。

这是编码第一个 fixture 获得回报的另一种方式。未来的装置很有可能更容易编码。这不是一个简单的改进保证。通常,测试夹具的第一个变体是简单的。

还有更多。。。

我们可能会遇到这样的情况:我们需要另一个与我们所构建的完全不同的测试夹具。在这一点上,投资于第一个测试夹具并没有同样的回报。但到了这个时候,我们将成为更有经验的测试编写者,并且在测试系统时更好地处理哪些有效,哪些无效。

到目前为止所做的所有工作都将提高我们的技能,这本身就是对测试夹具投资的巨大回报。

这只是关于建立一个数据库吗?

一点也不。如果我们的系统与 LDAP 服务器进行广泛的交互,我们可能需要编写一个 fixture 来清除目录结构并用测试数据加载它。

如果遗留系统足够灵活,我们可以将整个测试结构放入层次结构中的某个子节点中。但它也很可能期望数据存在于某个特定的位置。在这种情况下,我们可能需要开发一个脚本来启动一个单独的空 LDAP 服务器,然后在测试完成后关闭它。

设置和拆除 LDAP 服务器可能不是最快的,也不是最有效的测试设备。但是,如果我们花时间构建这个装置来授权自己编写自动化测试,我们最终将能够重构原始系统,将其与实时 LDAP 服务器分离。整个过程将提高我们的技能。这就是为什么创建原始测试夹具确实是一项投资。

如果你不相信测试的价值,你的团队也不会相信

被测试的开发者表现出热情。他们很兴奋地运行他们的测试套件,并看到事情以 100%的成功完成。这种情绪和自豪感往往会影响到其他开发人员。

但反过来也是如此。如果你对这一切都不感兴趣,也不传播消息,你的队友也不会意识到这一点。将自动测试添加到系统中的想法将悲惨地死去。

这不仅仅局限于我个人的经历。在 2010 年的 devLink 会议上,我参加了一个关于测试的开放空间讨论,并在十几个其他我没有合作过的开发人员中看到了这种反应(pythontestingcookbook.posterous.com/greetings-programs。测试人员在传达他们的测试经验时表现出某种程度的兴奋。那些对接受自动化测试持怀疑态度的人,眼睛里洋溢着喜悦,沉浸在其中。那些不感兴趣的人根本没有参加讨论。

如果您正在阅读这本书(当然是),那么您很有可能是团队中唯一对自动化测试感兴趣的人。你的队友可能听说过,但他们并不像你那样被这个想法刺痛。要将其添加到您的系统中,需要您进行大量投资。但不要局限于分享代码:

  • 当你取得进步和解决棘手问题时,表现出你的兴奋感
  • 把你的测试结果贴在你的墙上,让别人看到,以此来分享你的测试结果
  • 在休息室与同事聊天时谈论你的成就

测试不是一个冰冷、机械的过程。这是一个激动人心的发展领域。被测试的开发者迫不及待地想与他人分享它。如果你在寻找传播自动化测试之火的方法,最终其他人会对此感到热情,你会发现自己在一起谈论新的测试技术。

收获指标

启动一个电子表格,显示代码行、测试数、总测试执行时间和错误数,并跟踪每个版本。这些数字将保护你的投资。

怎么做。。。

这些高级步骤显示了如何随时间捕获度量:

  1. 创建一个电子表格来跟踪测试用例的数量、运行测试套件的时间、测试运行的日期、bug 和每个测试的平均时间。
  2. 将电子表格作为另一个受控工件检入代码库。
  3. 添加一些图表以显示测试时间与测试数量的曲线。
  4. 至少在每次发布时添加一行新数据。如果您可以更频繁地捕获数据,比如一次/周甚至一次/天,那就更好了。

它是如何工作的。。。

当您编写更多的测试时,测试套件将需要更长的时间来运行。但是你也会发现 bug 的数量会减少。您进行的测试越多,您进行测试的频率就越高,从而提高总体代码质量。捕获测试的指标可以作为硬证据,证明花费在编写和运行测试上的时间是一项合理的投资。

还有更多。。。

为什么我需要这份文件?难道我不知道测试是有效的吗?把它看作是你对质量主张的支持。几个月后,管理层可能会要求你加快进度。也许他们需要更快的东西,他们认为你只是在这个“测试东西”上花费了太多的时间。

如果你能拿出你的电子表格,展示 bug 是如何随着测试的努力而减少的,他们就没有什么可争辩的了。但是如果你没有这个,只是简单地说“测试让事情变得更好”,你可能会失去这个论点。

指标不仅仅是为了在管理层面前为自己辩护

我个人很高兴看到测试的增长和 bug 的减少。这是一种跟踪自己并掌握进展情况的个人方式。老实说,我上一任经理对自动化测试给予了全力支持。他有自己的成功标准,所以我从来不用拿出我的。

在自动测试中捕获错误

在修复发现的单行错误之前,请编写一个自动测试,并确保它是可重复的。这有助于建立与我们的系统之间的隔离,使其回归到我们过去修复的故障中。

怎么做。。。

这些高级步骤捕获了在修复自动化测试中的错误之前捕获错误的工作流:

  1. 当发现新的 bug 时,编写一个重新创建它的测试用例。不管测试用例是长时间运行的、复杂的还是与许多组件集成的。关键是要重现错误。
  2. 将其添加到您的测试套件中。
  3. 修复错误。
  4. 在签入更改之前,验证测试套件是否通过。

它是如何工作的。。。

将自动化测试引入以前从未有过的应用程序的最简单方法是一次测试一个 bug。这种方法确保新发现的 bug 不会在以后潜入系统。

测试可能会有一种松散的感觉,而不是全面的感觉,但这并不重要。重要的是,随着时间的推移,您将慢慢开发一个坚实的测试用例安全网,以验证系统是否按预期执行。

还有更多。。。

我没说这很容易。为没有考虑可测试性的软件编写自动测试是一项艰巨的工作。正如配方中提到的有总比没有好,第一个测试用例可能是最难的。但是随着时间的推移,随着您开发更多的测试,您将获得返回并重构内容的信心。如果你知道自己不能在不知情的情况下破坏事物,你肯定会感到有力量。

当需要添加全新模块时,您将做好准备

这种用测试用例捕获 bug 的方法很有用,但速度很慢。但这没关系,因为慢慢添加测试将给您时间以舒适的速度提高测试技能。

这在哪里有回报?嗯,最终,您需要向系统中添加一些新模块。这不是经常发生吗?到那时,您在测试和测试装置上的投资应该已经在提高现有代码的质量方面为您带来了回报。但在测试新模块时,您也将领先一步:

  • 您不仅会知道,而且会真正理解“面向测试的代码”的含义。
  • 您将能够以非常有效的方式同时编写代码及其测试。
  • 新模块将具有更高质量的领先优势,并且不需要像系统的传统部分那样努力“追赶”。

不要屈服于跳过测试的诱惑

如前所述,第一个测试用例将很难编写。在那之后的几天不会容易得多。这使得你很容易放弃你的手,跳过自动测试。但是如果你坚持下去,写一些有用的东西,那么你就可以继续努力,取得成功。

这听起来像是老生常谈,但如果你坚持一个月左右,你就会开始看到一些工作成果。这也是开始收获指标的好时机。记录你的进步并能够反思它可以提供积极的鼓励。

算法与并发分离

并发性很难测试,但大多数算法在解耦时都不是。

怎么做。。。

Herb Sutter 在 2005 年写了一篇文章,题为免费午餐已经结束,他指出微处理器在串行处理方面正接近物理限制,这将迫使开发人员转向并行解决方案(http://www.gotw.ca/publications/concurrency-ddj.htm )。

较新的处理器带有多个内核。为了构建可扩展的应用程序,我们不能再等待更快的芯片。相反,我们必须使用交替的并发技术。这一问题正在以多种语言进行讨论。Erlang 是最早出现的语言之一,它允许构建具有 9 个 9 的可用性的电信系统,这意味着每 30 年大约有 1 秒的停机时间。

它的一个关键特性是使用参与者之间发送的不可变数据。这提供了一个很好的隔离,并允许多个单元跨 CPU 核心运行。Python 的库提供了类似风格的解耦异步消息传递。最常见的两种是扭曲和卡迈利亚。

但在您深入使用这两种框架之前,有一点很重要:在测试算法的同时测试并发性是非常困难的。要使用这些库,您将注册发出消息的代码,并注册处理程序来处理消息。

它是如何工作的。。。

将算法与您选择的任何并发库的机制解耦是很重要的。这将使测试算法更加容易。这并不意味着您不应该进行负载测试,或者尝试使用实时数据回放场景使系统过载。

这意味着从大容量测试场景开始是错误的优先级。您的系统需要在自动测试用例中正确处理一个事件,然后才能处理一千个事件。

研究并发框架提供的测试选项

一个好的并发库应该提供良好的测试选项。找出它们并尽量充分利用它们。但别忘了验证您的自定义算法是否以简单、串行的方式工作。测试两侧将使您对系统在轻负载和重负载下的性能如预期的那样充满信心。

当测试套件运行时间过长时,暂停重构

当您开始构建测试套件时,您可能会注意到运行时变得相当长。如果时间太长,以至于您不愿意每天至少运行一次,那么您需要停止编码并专注于加速测试,无论是涉及测试本身还是测试中的代码。

怎么做。。。

这假设您已经开始使用以下一些实践构建测试套件:

  • 有总比没有好
  • 愿意投资测试夹具
  • 在自动测试中捕获错误

这些都是缓慢的开始步骤,可以开始向最初构建时没有任何自动测试的系统添加测试。进行自动化测试的一个权衡是编写相对昂贵的测试。例如,如果您的一个关键算法没有与数据库充分解耦,您将被迫编写一个测试用例,其中包括设置一些表、处理输入数据,然后对数据库的状态进行查询。

随着您编写更多的测试,运行测试套件的时间肯定会增加。在某些时候,您会觉得不太愿意花时间等待测试套件运行。因为测试套件只有在使用时才是好的,所以您必须暂停开发并对代码或测试用例本身进行重构,以加快速度。

这是我遇到的一个问题。我的测试套件最初运行大约需要 15 分钟。最终运行所有测试需要一个半小时。我一天只运行一次,甚至跳过了几天。有一天,我试图做大量的代码编辑。当大多数测试用例失败时,我意识到我没有足够频繁地运行测试套件,以检测哪一步破坏了测试。我被迫扔掉所有的代码编辑,重新开始。在继续之前,我花了几天时间重构代码和测试,将测试套件的运行时间缩短到可以容忍的 30 分钟。

它是如何工作的。。。

这是关键的衡量标准:当您对每天运行测试套件超过一次感到犹豫不决时,这可能是需要清理的迹象。测试套件一天要运行多次。

这是因为我们有相互竞争的兴趣:编写代码运行测试。认识到这一点很重要:

  • 要运行测试,我们必须暂停编码工作
  • 为了编写更多的代码,我们必须暂停测试工作

当测试占据我们日常日程的很大一部分时,我们必须开始选择哪个更重要。我们倾向于迁移到编写更多的代码,这可能是人们放弃自动化测试的关键原因,并认为它不适合他们的情况。

这很难,但如果我们能抵制这种简单的方法,转而对代码或测试进行重构,我们将被鼓励更频繁地运行测试。

还有更多。。。

重构的内容不是科学而是巫术。寻找能给我们带来好收益的机会是很重要的。理解这一点很重要,它可以是我们的测试代码,也可以是生产代码,或者是需要重构的两者的组合:

  • 性能分析可以告诉我们热点在哪里。重构或重写这些块可以改进测试。
  • 紧密耦合常常迫使我们引入比我们想要的更多的系统部分,例如数据库使用。如果我们能够找到将代码与数据库分离并用 mock 或 stub 替换它的方法,那么我们就可以更新相关的测试,以获得运行更快的测试套件。

从测试中获得的覆盖率可以有所帮助。所有这些方法对我们的代码质量都有积极的影响。更高效的算法带来更好的性能,更松散的耦合有助于降低长期维护成本。

另见

  • 愿意放弃一整天的改变

充分利用你的信心

在建立了足够的测试之后,您将有一种新的信心来重写一些大块代码,或者进行几乎涉及所有文件的散弹枪操作。去争取吧

怎么做。。。

当您构建更多的测试并每天运行几次时,您将开始了解您对系统的了解和不了解。更重要的是,当您编写了足够昂贵的、长时间运行的关于系统特定部分的测试时,您会强烈地希望重写该模块。

你还在等什么?这就是建立一个可运行的测试安全网的要点。了解模块的内部和外部信息可以帮助您了解如何攻击模块。您可以重写它,更好地解耦它的各个部分,或者其他任何需要使它更好地工作以及更好地支持测试的东西。

它是如何工作的。。。

虽然您可能有强烈的攻击代码的欲望,但也可能有一种平等和对立的感觉来抵制做出这样的更改。这是风险规避,我们都必须应对。我们希望避免陷入一种可能产生严重后果的局面。

假设我们已经建立了一个足够的安全网,现在是时候让代码参与进来并开始清理它了。如果我们在进行这些更改时经常运行测试套件,我们就可以安全地完成需要进行的更改。这将提高代码的质量,并可能加快测试套件的运行时间。

提示

在进行更改时,我们不必“全包”

利用我们的信心意味着我们进入代码库并对其进行更改,但这并不意味着我们进入测试肤浅和不充分的代码领域。我们可能需要清理几个区域,但我们应该只关注我们最有信心的部分。随着我们在未来添加更多测试,将来将有机会获得其他部件。

愿意放弃一整天的改变

花了一整天的时间进行更改,现在有一半的测试失败了,因为您更经常地忘记了测试套件?准备好扔掉这些变化。这就是自动化测试让我们做的…备份到一切都完美运行的时候。这会很痛苦,但下次您将记得更频繁地运行测试套件。

怎么做。。。

此配方假定您正在使用版本控制并进行定期提交。如果你已经两周没有做出承诺,这个想法是没有用的。

如果您每天至少运行一次测试套件,并且当它通过时,您提交了您所做的更改,那么就很容易备份到以前的某个点,例如一天的开始。

我已经做过很多次了。第一次是最难的。这对我来说是一个新想法,但我意识到软件的真正价值现在取决于我的自动化测试套件。下午,我在编辑了一半系统后,第一天运行了测试套件。超过一半的测试失败。

我试图深入研究并解决这个问题。问题是,我不知道这个问题是从哪里来的。我花了几个小时试图找到它。我开始明白,如果不浪费大量的时间,我是不可能弄明白的。

但我记得前一天一切都顺利地过去了。我最终决定放弃我的更改,运行测试套件验证所有通过的测试,然后勉强回家过一天。

第二天,我又开始讨论这个问题。只是这次我更频繁地进行测试。我成功地把它编码了。回顾当时的情况,我意识到这个问题只让我损失了一天。如果我试着度过难关,我可能会花一个星期的时间,最终还是会把东西扔掉。

它是如何工作的。。。

根据您的组织管理源代码管理的方式,您可能必须:

  • 只需删除分支机构或取消签出即可
  • 请与您的 CM 团队联系,删除分支机构或您当天所做的承诺

这不是一个真正的技术问题。源代码管理系统使得无论谁负责分支管理,都可以轻松做到这一点。困难的部分是做出放弃这些改变的决定。我们经常感到想要修复损坏的东西。我们越是努力使它进一步破裂,我们就越想修复它。在某种程度上,我们必须认识到,向前迈进的代价比后退并重新开始的代价更大。

敏捷的轴心从经典的瀑布式软件生产延伸到高度敏捷的过程。敏捷团队倾向于在较小的冲刺中工作,并在较小的块中提交。这使得丢掉一天的工作更令人愉快。任务越大,发布周期越长,自两周前开始任务以来您的更改未被签入的可能性就越大。

相信我;放弃两周的工作和放弃一天是完全不同的。我决不会主张放弃两周的工作。

核心思想是在测试套件未通过的情况下不要回家。如果这意味着你必须扔掉一些东西来实现它,那么这就是你必须做的。在一个新特性准备发布之前,它真的会让代码/测试变得更加重要。

还有更多。。。

我们还需要反思为什么我们没有足够频繁地运行测试套件。这可能是因为测试套件的运行时间太长,而您正在犹豫是否要用完这段时间。当测试套件需要太长时间才能运行时可能需要暂停重构。我真正学到这一课的时候是我的测试套件运行了一个半小时。当我看完这整件事后,我意识到我需要加快速度,并花了大概一两周的时间将其缩短到可以忍受的 30 分钟。

这与“有总比没有好”的关系如何

在本章前面,我们讨论了编写一个测试用例,为了实现一些自动化测试,运行这个测试用例可能会非常昂贵。如果我们的测试变得过于昂贵以至于时间紧迫怎么办?毕竟,我们刚才所说的不能导致我们正在处理的局面吗?

编写一点代码/进行一点测试似乎是一种非常缓慢的方式。这可能是许多遗留系统从不接受自动测试的原因。我们必须爬的山很陡。但是,如果我们能够坚持下去,开始构建测试,确保它们在一天结束时运行,然后最终停下来重构代码和测试,我们最终可以在更好的代码质量和系统信心之间达成令人满意的平衡。

另见

  • 有总比没有好
  • 当测试套件花费太长时间时,暂停重构

与其拍摄 100%的覆盖率,不如尝试稳定增长

如果没有覆盖率分析,你将不知道自己在做什么。然而,目标不要太高。相反,关注于逐渐增加。您会发现,随着时间的推移,您的代码会变得更好,甚至数量会下降,而质量和覆盖率会稳步提高。

怎么做。。。

如果你从一个没有测试的系统开始,不要把注意力集中在一个高得离谱的数字上。我在一个覆盖率为 16%的系统上工作。一年后,我把它提高到 65%。这远未达到 100%,但由于在自动测试采集指标中捕获了一个 bug,系统的质量得到了突飞猛进的提高。

有一次,我和我的经理讨论代码的质量,他给我看了一份他自己开发的报告。他在监督的每个应用程序的每个版本上都运行了一个代码计数工具。他说我的代码计数有一个独特的形状。所有其他工具的代码行都在不断增加。我的收入增长了,达到顶峰,然后开始下降,而且还在下降。

尽管我的软件比以往做得更多,但这种情况还是发生了。这是因为我开始扔掉未使用的特性、糟糕的代码,并在重构过程中清理掉残缺不全的东西。

它是如何工作的。。。

通过慢慢地构建自动化测试套件,您将逐渐覆盖更多的代码。通过保持对构建具有相应测试的质量代码的关注,覆盖率将自然增长。当我们转向关注覆盖率报告时,我们可能会更快地增加数字,但这将更倾向于人为。

不时地,当你利用你的自信并重写区块时,你应该感到有能力扔掉旧的垃圾。这也将以健康的方式增加您的覆盖率指标。

所有这些因素都将提高质量和效率。虽然您的代码最终可能会达到峰值,然后下降,但由于新特性,它最终会再次增长并不是不现实的。到那时,覆盖率可能会高得多,因为现在您正在构建全新的功能,与测试一起进行,而不仅仅是维护遗留部件。

随机破坏你的应用程序可以产生更好的代码

避免失败的最好方法是不断失败。-Netflix(http://techblog.netflix.com/2010/12/5-lessons-weve-learned-using-aws.html

怎么做。。。

Netflix 制造了一种工具,他们称之为混沌猴子。它的工作是随机杀死实例和服务。这迫使开发人员确保他们的系统能够顺利、安全地发生故障。

要构建我们自己的版本,我们需要它做的一些事情包括:

  • 随机杀死进程
  • 在接口点注入错误数据
  • 关闭分布式系统之间的网络接口
  • 向子系统发出关闭命令
  • 通过使用过多数据重载接口点来创建拒绝服务攻击

这是一个起点。这个想法是在你能想象的任何地方注入错误。这可能需要编写脚本、cron 作业或任何导致这些错误发生的必要手段。

它是如何工作的。。。

考虑到远程系统有可能在生产环境中不可用,我们应该介绍在开发环境中实现这一点的方法。这将鼓励我们在系统中编写更高的容错代码。

在我们引入像 Netflix 一样随机运行的“混沌猴子”之前,我们需要看到我们的系统能够手动处理这些情况。例如,如果我们的系统包括两台服务器之间的通信,公平的测试是将网络电缆拔到一个盒子上,模拟网络故障。当我们验证我们的系统能够以可接受的方式继续工作时,我们就可以添加脚本来自动并最终随机地完成这项工作。

审计日志是验证我们的系统是否在处理这些随机事件的重要工具。如果我们可以读取显示强制网络关闭的日志条目,然后查看具有类似时间戳的日志条目,我们就可以轻松评估系统是否处理了这种情况。

在中构建之后,我们可以处理下一个错误,将其随机引入系统。通过遵循这个周期,我们可以建立系统的健壮性。

还有更多。。。

这并不完全适合自动化测试领域。这也是很高的水平。由于要注入的错误数据类型需要对实际系统有深入的了解,因此很难深入了解更多细节。

这与模糊测试相比如何?

模糊测试是一种将无效、意外和随机数据注入我们的软件(的输入点的测试方式 http://en.wikipedia.org/wiki/Fuzz_testing 。如果应用程序失败,则视为失败。如果没有,那么它已经过去了。这种类型的测试也朝着类似的方向发展,但 Netflix 撰写的博客文章似乎比简单地注入不同的数据走得更远。他们谈论杀死实例和中断分布式通信。基本上,你能想到的任何事情都会在生产中发生,我们应该尝试在测试台上进行复制。

熔断器https://bitbucket.org/haypo/fusil 是一个 Python 工具,旨在提供模糊测试。您可能需要调查它是否对您的项目需求有用。

有什么工具可以帮助您完成这项工作吗?

Jester(用于 Java)、Pester(用于 Python)和 Nester(用于 C#)用于进行突变测试(http://jester.sourceforge.net/ )。这些工具找出测试用例中没有包含的代码,修改源代码,并重新运行测试套件。最后,它给出了一个关于什么被改变,什么通过了,什么没有通过的报告。它可以以覆盖工具无法做到的方式说明我们的测试套件所涵盖和未涵盖的内容。

这不是一个完整的“混乱猴子”,但它提供了一个领域的帮助,试图“打破系统”,并迫使我们改善我们的测试制度。要真正构建一个完整的系统可能不适合某些测试项目,因为它需要根据要运行的环境编写自定义脚本。