我的Rails应用程序规格因为默认语言设置错误而随机失败。

10

不时地,我的Rails应用程序的某些规范似乎会随机失败,因为突然英语不再是默认语言,而是德语:

   expected: "Project test customer - Project test name (Audit, Access for all, 2015-06-15).pdf"
        got: "Project test customer - Project test name (Audit, Zugang für alle, 2015-06-15).pdf"

可以看到,“Access for all”这部分突然变成了“Zugang für alle”。我在谷歌上搜寻了解决方案,似乎发现 I18n.locale 是一个全局对象,所以当在一个 spec 中进行更改时,它会一直保留。

这个问题并不总是发生,但是我可以通过像这样指定种子来复现它:rspec --seed 51012。因此,真的似乎是某个 spec 在之前(或之后)执行时出现了问题。

我有一个功能规范,测试是否可以更改语言环境,就像这样:

it 'offers contents in german' do
  visit root_path(locale: :de)

  expect(page).to have_content 'Willkommen'
end

我怀疑这可能是有问题的规范,如果它在早期运行,则会对其他规范产生影响。

我希望通过将规范中的语言设置回默认值来解决这个问题,就像这样:

it 'offers contents in german' do
  visit root_path(locale: :de)

  expect(page).to have_content 'Willkommen'

  I18n.locale = :en
end

没用,这个也不行:

it 'offers contents in german' do
  visit root_path(locale: :de)

  expect(page).to have_content 'Willkommen'
  visit root_path(locale: :en)
end

我现在有些不知所措。我该如何调试这种情况,以便确定问题的根源并修复它(或者至少解决它)?

更新

使用Dave的答案(rspec --bisect)我找到了问题所在。

# application_controller_spec.rb
describe ApplicationController do
  controller(ApplicationController) do
    def index
      render text: 'Hello World'
    end
  end

  describe 'locale parameter' do
    it 'is set to english when not available in the request' do
      get :index
      expect(I18n.locale).to eq :en
    end

    it 'can be set through the request' do
      get :index, locale: :de
      expect(I18n.locale).to eq :de
    end
  end
end

根据这些规范运行的顺序不同,区域设置会在后续规范中设置为:de:en

我用BoraMa建议的代码片段进行了修复:

RSpec.configure do |config|
  config.after(:each) { I18n.locale = :en }
end

我仍然有点惊讶,RSpec/Rails自己没有自动完成这个操作...


你实际上没有展示出失败的规格(spec)- 这可能有所帮助。 - Yule
另外,尝试将你认为引起问题的代码和无法正常运行的代码添加到一个rspec文件中,然后只运行此文件。这样你就可以验证是哪个spec引起了问题,而不用运行整个测试套件。 - Yule
2
在每个测试之前,我会使用debug-print输出当前的I18n.locale(例如 before(:each) { puts I18n.locale }),这样你就可以找到问题所在了。此外,我会使用after(:each) { I18n.locale = :en }来在每个测试后重置语言环境。这两段代码应该放在spec/spec_helper.rbspec/rails_helper.rb中。 - Matouš Borák
2
我认为你可能在掩盖问题 - 有什么保证默认语言环境不能在生产中通过等效的请求序列进行更改呢? - Frederick Cheung
我不明白你的意思,Frederick。 - Joshua Muheim
1个回答

6

注释掉你怀疑的规范,然后运行rspec --seed 51012。如果测试通过,则知道罪犯是哪部分代码。

如果不行,就需要用rspec --bisect。执行:

rspec --seed 51012 --bisect

让RSpec找到最小的一组示例(可能是2个),以重现故障。然后您可以决定如何处理罪犯。

此功能在RSpec 3.3中可用,并在RSpec 3.4中得到改进。更多信息请参见:https://relishapp.com/rspec/rspec-core/docs/command-line/bisect


哇,我知道git bisect但不知道rspec --bisect!这是个好消息。我找到了问题并更新了问题描述。谢谢! - Joshua Muheim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接