进行TDD时的性能测试最佳实践?

时间:2009-04-15 13:11:17

标签: performance tdd automated-tests integration-testing

我正在开展一个非常需要进行性能调整的项目。

如果我的优化不能提高程序的速度,如何编写失败的测试?

详细说明一下:

问题不在于发现要优化的部分。我可以使用各种分析和基准测试工具。

问题是使用自动测试来记录特定优化确实具有预期效果。如果我可以使用测试套件以后发现可能的性能回归,那也是非常可取的。

我想我可以运行我的分析工具来获取一些值,然后断言我的优化代码会产生更好的值。然而,明显的问题是基准值不是硬值。它们因当地环境而异。

那么,总是使用同一台机器进行这种集成测试的答案是什么?如果是这样,您仍然必须在结果中允许一些模糊性,因为即使在相同的硬件上,基准测试结果也会有所不同。那怎么考虑这个呢?

或许答案是保留程序的旧版本并比较前后的结果?这将是我首选的方法,因为它主要与环境无关。有没有人有这种方法的经验?我想如果最新版本的性能至少与前一版本一样好,那么只有保留一个旧版本才能通过所有测试。

9 个答案:

答案 0 :(得分:5)

我怀疑应用TDD来提高性能是一个错误。无论如何,使用它来获得良好的设计和工作代码,并使用在TDD过程中编写的测试来确保持续的正确性 - 但是一旦你有完善的代码和一套可靠的测试,你就会处于良好的状态调整,以及不同(来自TDD)的技术和工具适用。

TDD为您提供良好的设计,可靠的代码和测试覆盖安全网。这会让你进入一个调整的好地方,但我认为,由于你和其他人所引用的问题,它根本不会让你在调整之路上走得更远。我说这是TDD和实践者的忠实粉丝和支持者。

答案 1 :(得分:3)

首先,您需要为可接受的性能建立一些标准,然后您需要设计一个在使用现有代码时将失败该标准的测试,然后您需要调整代码以获得性能,直到它通过测试。您可能会有多个性能标准,您当然应该有多个测试。

答案 2 :(得分:3)

在许多服务器应用程序中(可能不是您的情况),性能问题仅在并发访问和负载下才会出现。因此,测量例程执行的绝对时间并尝试改进它并不是很有帮助。即使在单线程应用程序中,此方法也存在问题。测量绝对常规时间取决于平台提供的时钟,这些是not always very precise;你最好依赖日常的平均时间。

我的建议是:

  • 使用分析来识别执行次数最多且占用时间最多的例程。
  • 使用JMeterGrinder等工具来详细说明代表性测试用例,模拟并发访问,使应用程序处于压力之下并测量(更重要的)吞吐量和平均响应时间。从外部角度看,这将使您更好地了解应用程序的行为方式。

虽然您可以使用单元测试来建立应用程序的一些非功能方面,但我认为上面给出的方法将在优化过程中提供更好的结果。在单元测试中放置与时间相关的断言时,您必须选择一些非常近似的值:时间可能会根据您用于运行单元测试的环境而有所不同。您不希望测试失败只是因为您的某些同事正在使用劣质硬件。

调整就是要找到合适的东西来调整。您已经拥有一个正常运行的代码,因此放置与性能相关的断言 a posteriori 而不建立关键的代码段可能会导致您浪费大量时间来优化应用程序的非必要部分。

答案 3 :(得分:2)

记录当前代码的运行时间。

if (newCode.RunningTime >= oldCode.RunningTime) Fail

答案 4 :(得分:1)

在CI服务器中运行测试+分析。您还可以定期运行负载测试。

你担心差异(正如你所提到的),所以它不是关于定义绝对值。有一个额外的步骤,将此运行的性能度量与上一个构建的性能度量进行比较,并将差异报告为%。您可以为重要的时间变化引发红旗。

如果您对性能感到担忧,那么您应该有明确的目标,并且要坚持这些目标。您应该测量那些在整个系统上进行测试的人。即使您的应用程序逻辑很快,您也可能会遇到视图问题而导致您错过目标。您也可以将它与差异方法结合起来,但对于这些方法,您对时间变化的容忍度会降低。

请注意,您可以在开发计算机中运行相同的进程,只使用该计算机中的先前运行,而不是开发人员之间的共享进程。

答案 5 :(得分:0)

对于调整本身,您可以直接比较旧代码和新代码。但是不要保留两份副本。这听起来像是一场噩梦。此外,您只是将一个版本与另一个版本进行比较。功能的改变可能会降低您的功能,这对用户来说是可以接受的。

就我个人而言,我从未见过类型'必须比上一版更快'的性能标准,因为它很难衡量。

你说'严重需要性能调整'。哪里?哪个查询?哪个功能?谁说,业务,用户?什么是可接受的表现? 3秒? 2秒? 50毫秒?

任何性能分析的起点是定义通过/失败标准。完成后,您可以自动执行性能测试。

为了可靠性,您可以使用(简单)统计方法。例如,在相同条件下运行相同的查询100次。如果95%的人在n秒内返回,那就是通行证。

就个人而言,我会在集成时从标准机器或集成服务器本身执行此操作。记录每个测试的值(巡航控制有一些很好的功能)。如果这样做,您可以看到性能随着时间的推移以及每次构建的进展情况。你甚至可以制作图表。管理人员喜欢图表。

在进行性能测试时,无论您是否进行自动化测试,都必须拥有稳定的环境。无论你如何发展(TDD,瀑布等),你都会遇到这个特殊问题。

答案 6 :(得分:0)

还没有面对这种情况;)但是,如果我这样做,这就是我如何去做。 (我想我是从Dave Astel的书中选择的)

步骤#1:提出“可接受的性能”规范,例如,这可能意味着“用户需要能够在N秒(或毫秒)内完成Y” 步骤2:现在写一个失败的测试..使用你的友好计时器类(例如.NET有StopWatch类)和Assert.Less(actualTime, MySpec)
步骤3:如果测试已经通过,那么你已经完成了。如果是红色,则需要优化并使其变绿。一旦测试变为绿色,性能现在就“可接受”。

答案 7 :(得分:0)

肯特贝克和他的团队在TDD中自动完成了所有测试。

此处进行性能测试我们也可以在TDD中自动化测试。

性能测试中的标准是我们应该测试是或否的情况

如果我们知道这些规格很好,我们也可以在TDD中自动化它们

答案 8 :(得分:0)

虽然我大致同意Carl Manaster的回答,但借助现代工具,可以获得TDD为性能测试中的功能测试提供的一些优势。

使用大多数现代性能测试框架(我的大部分经验都是Gatling,但我相信大多数性能测试框架的新版本都是如此),可以将自动化性能测试集成到持续集成构建中,并对其进行配置,以便在不满足性能要求时CI构建将失败。

因此,如果可以事先同意您的性能要求(某些应用程序可能由与用户或客户商定的SLA驱动),如果更改产生了性能问题,则可以为您提供快速反馈,并确定区域这需要改进性能。

良好的性能要求是“当每小时有5000个订单时,95%的用户旅程应包括不超过10秒的等待时间,并且没有超过1秒的屏幕转换”。

这还依赖于在CI管道中部署到类似生产的测试环境。

但是,使用性能要求以与功能要求相同的方式驱动开发可能仍然不是一个好主意。通过功能需求,您通常可以了解应用程序在运行之前是否通过测试,并且尝试编写您认为会通过的代码是明智的。有了表现,trying to optimize code whose performance hasn't been measured is a dubious practice。您可以使用性能结果在某种程度上推动应用程序开发,而不是性能要求