You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rspec使用--only-failures时重复运行所有测试问题排查

问题修复:RSpec重试失败用例时重复执行所有用例

问题现象

封装RSpec用于Selenium测试的Ruby gem,尝试实现失败用例重试逻辑,但第二次运行--only-failures时,不仅执行了失败用例,还出现重复执行的情况(输出显示4个示例,实际仅2个)。调试发现spec_helper.rb仅加载一次,且未出现未设置持久化路径的错误。

相关代码

spec_helper.rb

RSpec.configure do |config|
  config.example_status_persistence_file_path = "logs/LO_RunResults.txt"
end

my_spec.rb

it "should pass" do
  expect(true).to be true
end

it "should fail" do
  expect(false).to be true
end

rspec_runner.rb

test_results_file = "#{File.expand_path(Dir.pwd)}/logs/RunResults.txt"
File.delete(test_results_file) if File.exist?(test_results_file)

args = %w(-r spec_helper --order defined --format CustomFormatter --format documentation)
RSpec::Core::Runner.run(args, $stderr, $stdout)

# RunResults.txt is generated from previous run

args = %w(-r spec_helper --order defined --format CustomFormatter --format documentation --only-failures)
RSpec::Core::Runner.run(args, $stderr, $stdout)

运行输出

#################### Running spec_helper ####################

Test Suite - my_spec
  Positive Tests
    should pass
    should fail (FAILED - 1)

Failures:

  1) Test Suite - my_spec Positive Tests should fail
     Failure/Error: expect(false).to be true
     
       expected true
            got false
     # ./spec/my_spec.rb:59:in `block (3 levels) in <top (required)>'

Finished in 0.06265 seconds (files took 0.71696 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/my_spec.rb:58 # Test Suite - my_spec Positive Tests should fail

Run options: include {:last_run_status=>"failed"}

Test Suite - my_spec
  Positive Tests
    should pass
    should fail (FAILED - 2)

Failures:

  1) Test Suite - my_spec Positive Tests should fail
     Got 2 failures:

     1.1) Failure/Error: expect(false).to be true
          
            expected true
                 got false
          # ./spec/my_spec.rb:59:in `block (3 levels) in <top (required)>'

     1.2) Failure/Error: expect(false).to be true
          
            expected true
                 got false
          # ./spec/my_spec.rb:59:in `block (3 levels) in <top (required)>'

  2) Test Suite - my_spec Positive Tests should fail
     Got 2 failures:

     2.1) Failure/Error: expect(false).to be true
          
            expected true
                 got false
          # ./spec/my_spec.rb:59:in `block (3 levels) in <top (required)>'

     2.2) Failure/Error: expect(false).to be true
          
            expected true
                 got false
          # ./spec/my_spec.rb:59:in `block (3 levels) in <top (required)>'

Finished in 0.03786 seconds (files took 0.79882 seconds to load)
4 examples, 2 failures

Failed examples:

rspec ./spec/my_spec.rb:58 # Test Suite - my_spec Positive Tests should fail
rspec ./spec/my_spec.rb:58 # Test Suite - my_spec Positive Tests should fail


Process finished with exit code 0

问题根源

  • 持久化文件路径不匹配:spec_helper.rb中配置的持久化文件是logs/LO_RunResults.txt,但rspec_runner.rb中操作的是logs/RunResults.txt,两者文件名不一致,导致第二次运行时无法读取到正确的失败用例记录,RSpec fallback执行所有用例。
  • 同一进程重复运行RSpec的状态污染:RSpec的设计不支持在同一个Ruby进程内多次调用RSpec::Core::Runner.run,因为全局的示例定义、配置等状态不会自动重置,第二次运行时会重复注册之前的示例,导致输出中出现4个示例(实际仅2个)的异常。

修复方案

1. 统一持久化文件路径

修改spec_helper.rb,将持久化文件路径与runner脚本保持一致:

RSpec.configure do |config|
  config.example_status_persistence_file_path = "logs/RunResults.txt"
end

2. 使用子进程执行RSpec

修改rspec_runner.rb,用子进程替代同一进程内的重复调用,彻底避免状态污染:

test_results_file = "#{File.expand_path(Dir.pwd)}/logs/RunResults.txt"
File.delete(test_results_file) if File.exist?(test_results_file)

# 第一次运行
system("rspec -r spec_helper --order defined --format CustomFormatter --format documentation")

# 第二次运行失败用例
system("rspec -r spec_helper --order defined --format CustomFormatter --format documentation --only-failures")

如果你的项目使用bundle管理依赖,将命令改为bundle exec rspec ...即可。

验证效果

修复后,第二次运行--only-failures只会执行失败的那个示例,输出不会出现重复用例,且仅重试失败测试。

内容的提问来源于stack exchange,提问作者kroe761

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:05:20