如何诊断间歇性 Rspec 故障(不依赖于顺序)的原因?

ico*_*ast 1 rspec

我知道rspec --bisect根据示例运行的顺序来隔离间歇性失败的规范。但我在遗留应用程序中遇到了一个案例(我以前从未在这个代码库中工作过),即使在隔离\xe2\x80\x94 中运行时,规范也会间歇性地失败,因此序列不是一个因素。

\n

换句话说,如果我跑

\n
rspec ./spec/services/locate_missing_approver_service_spec.rb:5\n
Run Code Online (Sandbox Code Playgroud)\n

它可能会在 10 次中失败 1 次。这个 10% 的数字是根据我运行此程序的经验猜测的,但如果我有一种准确收集这样的统计数据的方法,它可能会很有用,这样我就可以用来git bisect确定间歇性的位置失败开始。

\n

目前,我正在手动运行一个函数来检查失败是否发生在任何给定的提交或任何临时更改的代码中,并且我可以扩展它来收集统计信息,但我不确定这是否是最好的路径向下。

\n
function test-flaky-spec() {\n  while true; do\n    rspec ./spec/services/locate_missing_approver_service_spec.rb:5\n    if [[ $? -ne 0 ]]; then\n      break\n    fi\n    sleep 0.1\n  done\n}\n
Run Code Online (Sandbox Code Playgroud)\n

所以问题实际上可以归结为:

\n

对于这种情况,是否有普遍接受的故障排除技术?

\n

ari*_*ver 5

这个问题是在 RSpec 的背景下提出的。这个答案比这个更广泛。它应该适用于任何语言的任何自动化测试套件。

片状测试是指不一致地失败的测试。不稳定的主要原因是对环境中某些东西的依赖性,这些东西从一次运行到另一次运行都会发生变化。以下是测试运行之间环境可能发生变化的三种方式:

  • 非决定论
  • 泄漏
  • 比赛条件

非决定论

测试有时依赖于环境的非确定性部分,例如系统时钟、随机数或对网络资源的访问。异步代码(如文件 I/O)也是不确定的,可能会导致失败。

这种片状的好处是你可以在本地独立地重现它。因此,您唯一需要做的就是找到环境中正在变化的事物并模拟它。例如:

  • 如果您使用系统时钟,请在测试期间冻结时间以确保确定的结果。
  • 如果您使用随机数生成器,请模拟它并仅返回当前测试用例中所需的值。
  • 如果您正在使用网络,请不要这样做。模拟网络调用并返回与正在运行的测试匹配的有效负载。
  • 如果您正在测试异步代码,请不要这样做。测试时强制其同步。

泄漏

泄漏测试是一种修改某些全局状态,然后无法自行清理的测试。运行后,所有后续测试都是从不可预测的环境开始的,这可能会导致其中一些测试失败。需要注意的一些全局状态是环境变量、类变量和全局数据存储,例如 memcache、redis 或数据库。

泄漏测试更难确定。它们可以在本地重现,但由于它们依赖于顺序,因此在单独运行时不会失败。调试这些故障的关键是在测试开始时检查环境的状态,以确保它符合您的期望。

永久解决这些故障的关键在于找出哪些测试没有自行清理。某些工具(如 RSpec)能够“平分”测试套件,以确定哪些特定测试以特定顺序运行将导致下游测试始终失败。这是一个很大的帮助,但并不总是能带来明确的答案。多个泄漏测试的组合可能会导致下游测试失败。

竞赛条件

竞争条件测试是一种在执行期间利用共享资源的测试。因此,当与其他测试(通常在 CI 中)并行运行时,任何依赖此共享资源的测试都可能会在并行执行时通过另一个测试更改它们期望的值。

这种失败是最难重现的。通常,您不会在本地并行运行测试。而且,由于它们的并行性质,您将无法单独重现这些问题。不过,一旦发现失败,请查找测试可能在何处使用某些全局可用的共享资源,并找到停止使用它的方法。例如,尝试为每个测试提供其自己的共享资源内存中实现。

概括

不稳定几乎总是可以追溯到测试,这取决于环境中意外变化的某些东西。以下是避免不稳定的一些最佳实践:

  • 模拟非确定性系统资源
  • 自己清理后
  • 避免使用全局状态
  • 优先使用一次性内存存储而不是持久共享资源

另外,使用本指南来确定要寻找哪种片状:

  • 如果您可以在本地独立地重现,那么您可能正在处理非确定性测试。
  • 如果您可以在本地重现,但不能单独重现,那么您可能会遇到泄漏测试。如果您的工具支持 bisect,请利用它来帮助识别哪些测试处于泄漏状态。
  • 而且,如果您无法在本地重现并且问题仅发生在 CI 中,那么您可能正在处理竞争条件。