我将回答你问题的第三部分,因为我曾经成功地执行过几次。
当性能是关键要求时,如何应用红-绿-重构?
- 编写钉住测试来捕捉回归,包括您计划更改和其他可能因您的更改而变慢的方法。
- 编写失败的性能测试。
- 进行性能改进,经常运行所有测试。
- 更新您的固定测试以更紧密地固定性能。
编写钉住测试
创建一个像这样的帮助方法,以测量您想要固定的内容。
private TimeSpan Time(Action toTime)
{
var timer = Stopwatch.StartNew();
toTime();
timer.Stop();
return timer.Elapsed;
}
然后编写一个测试,断言您的方法不需要任何时间:
[Test]
public void FooPerformance_Pin()
{
Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0));
}
如果它失败了(故障消息中显示实际经过的时间),请使用略高于实际时间的时间更新时间。重新运行,就可以通过测试了。对于其他可能会受到更改影响的功能,重复这个步骤,最终得到类似下面的结果。
[Test]
public void FooPerformance_Pin()
{
Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0.8));
}
[Test]
public void BarPerformance_Pin()
{
Assert.That(Time(()=>fooer.Bar()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(6));
}
编写一个失败的性能测试
我喜欢把这种测试称为“引诱测试”。它只是针对固定测试的第一步。
[Test]
public void FooPerformance_Bait()
{
Assert.That(Time(()=>fooer.Foo()), Is.LessThanOrEqualTo(TimeSpan.FromSeconds(0));
}
现在,着手进行性能改进。每次尝试改进后都要运行所有测试(包括锁定和诱饵测试)。如果成功了,你会看到诱饵测试的失败输出中的时间减少了,而你的锁定测试都不会失败。
当你对改进满意时,更新你所更改代码的锁定测试,并删除诱饵测试。
现在你该怎样处理这些测试呢?
最不必担心的做法是将这些测试标记为Explicit属性,并将它们保留到下次检查性能时使用。
另一方面,为这种类型的测试创建一个相当好控制的 CI 子系统,是监测性能回归的一种非常好的方法。根据我的经验,人们实际上更担心它们“由于其他原因导致 CPU 负载随机失败”而不是实际故障。这种努力的成功更多地取决于团队文化而不是你对环境的控制能力。