我将回答你问题的第三部分,因为我已经多次成功地做到了这一点。
当性能是关键要求时,您将如何应用 red->green->refactor?
- 编写固定测试以捕获回归,了解您计划更改的内容以及可能因更改而减慢的其他方法。
- 编写一个失败的性能测试。
- 提高性能,经常运行所有测试。
- 更新您的固定测试以更紧密地固定性能。
编写固定测试
创建一个像这样的辅助方法来计时您想要固定的内容。
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));
}
现在,致力于性能改进。在每次尝试性改进后运行所有测试(固定和诱饵)。如果您成功了,您会在 baiting 测试的失败输出中看到时间减少,并且您的所有 pinning 测试都不会失败。
当您对改进感到满意时,为您更改的代码更新 pinning 测试,并删除 baiting 测试。
您现在如何处理这些测试?
最不担心的事情是用Explicit属性标记这些测试,并在下次要检查性能时保留它们。
在工作范围的另一边,在 CI 中创建一个控制良好的子系统来运行这些测试是监控性能回归的一个非常好的方法。以我的经验,与实际故障相比,人们更担心它们“由于其他原因导致 CPU 负载随机故障”。这种努力的成功更多地取决于团队文化,而不是你对环境的控制能力。