我知道
rspec --bisect
根据示例运行的顺序隔离间歇性失败的规范。但我有一个遗留应用程序的案例(我以前从未在这个代码库中工作过),即使在孤立运行时,规范也会间歇性地失败——所以顺序不是一个因素。
换句话说,如果我跑
rspec ./spec/services/locate_missing_approver_service_spec.rb:5
它可能会在 10 次中失败 1 次。这个 10% 的数字是根据我运行它的经验的猜测,但如果我有一种像这样准确收集统计数据的方法,它可能会有用,所以我可以使用
git bisect
来确定间歇性故障从哪里开始。
目前我正在手动运行一个函数来检查失败是否发生在任何给定的提交或任何临时更改的代码中,我可以扩展它来收集统计信息,但我不确定这是否是最好的途径下去吧。
function test-flaky-spec() {
while true; do
rspec ./spec/services/locate_missing_approver_service_spec.rb:5
if [[ $? -ne 0 ]]; then
break
fi
sleep 0.1
done
}
所以问题真的归结为:
对于这种情况,是否有普遍接受的故障排除技术?
这个问题问的是RSpec的上下文。这个答案比那个更广泛。它应该适用于任何语言的任何自动化测试套件。
片状测试是不一致地失败的测试。不稳定的主要原因是对环境中某些东西的依赖性会从一次运行到另一次运行发生变化。以下是测试运行之间环境可能发生变化的三种方式:
测试有时依赖于环境的非确定性部分,如系统时钟、随机数或对网络资源的访问。
这种脆弱性的好处是你可以在本地和隔离地重现它。因此,您唯一需要做的就是找到环境中发生变化的事物并模拟它。例如:
泄漏测试是一种修改某些全局状态,然后无法自行清理的测试。它运行后,所有后续测试都是从一个不可预测的环境开始的,这可能会导致其中一些测试失败。一些需要注意的全局状态是环境变量、类变量和全局数据存储,如 memcache、redis 或数据库。
有漏洞的测试更难确定。它们可以在本地复制,但因为它们依赖于顺序,所以它们在单独运行时不会失败。调试这些故障的关键是在测试开始时检查环境状态,以确保它符合您的预期。
永久解决这些失败的关键在于找出哪些测试没有自行清理。某些工具(如 RSpec)能够“平分”测试套件,以确定以何种特定顺序运行的特定测试将导致下游测试始终失败。这是一个很大的帮助,但并不总能得出明确的答案。可能是多个泄漏测试的组合导致下游测试失败。
竞争条件测试是在执行期间利用共享资源的测试。因此,当与其他测试(通常在 CI 中)并行运行时,任何依赖此共享资源的测试都可能具有他们期望的值,而另一个测试会在并行执行时更改它们。
这种故障是最难重现的。通常,您不会在本地并行运行测试。而且,由于它们的并行性质,您将无法单独重现这些问题。但是,一旦发现失败,请查找测试可能在何处使用某些全局可用的共享资源,并找到停止使用它的方法。例如,尝试在共享资源的内存实现中为每个测试提供自己的测试。
脆弱性几乎总是可以追溯到测试,这取决于测试环境中的某些意外变化。这里有一些避免片状的最佳实践:
此外,如果使用本指南来确定要寻找哪种薄片: