如何避免Rspec共享示例'先前定义'的警告?

时间:2015-07-03 14:43:00

标签: ruby-on-rails ruby testing rspec warnings

我正在尝试学习如何使用Rspec的共享示例功能,并在运行测试时收到警告:

WARNING: Shared example group 'required attributes' has been previously defined at:
  /Users/me/app/spec/support/shared_examples/required_attributes_spec.rb:1
...and you are now defining it at:
  /Users/me/app/spec/support/shared_examples/required_attributes_spec.rb:1
The new definition will overwrite the original one.
....

我已经阅读了我认为有关此问题的文档here,但我无法理解它/看到我案例的内容。

以下是我的共享示例:

# spec/support/shared_examples/required_attributes_spec.rb

shared_examples_for 'required attributes' do |arr|
  arr.each do |meth|
    it "is invalid without #{meth}" do
      subject.send("#{meth}=", nil)
      subject.valid?
      expect(subject.errors[meth]).to eq(["can't be blank"])
    end
  end
end

我正在尝试在User模型和Company模型中使用它。这是它的样子:

# spec/models/user_spec.rb

require 'rails_helper'

describe User do
  subject { build(:user) }
  include_examples 'required attributes', [:name]
end

# spec/models/company_spec.rb

require 'rails_helper'

describe Company do
  subject { build(:company) }
  include_examples 'required attributes', [:logo]
end

根据我上面链接的Rspec文档中的建议,我尝试将include_examples更改为it_behaves_like,但这没有帮助。我还完全评论了company_spec.rb因此只有一个使用共享示例的规范,我仍然收到警告。

任何人都可以帮助我看看这里发生了什么,以及在这种情况下我应该做些什么来避免警告?

2 个答案:

答案 0 :(得分:26)

我在Rspec Github的issue找到了答案:

  

以防有人谷歌和土地在这里。如果把你的文件   共享示例到support文件夹中没有修复以下内容   错误...确保您的文件名不以_spec.rb.

结尾

答案 1 :(得分:0)

作为对此的后续处理,我在包含的共享上下文中遇到了问题,文件名_spec.rb 结尾,并且是通过 require_relative 手动加载的,而不是自动加载。就我而言,问题是复制粘贴问题。测试如下:

RSpec.shared_examples 'foo' do
  RSpec.shared_examples 'bar' do
    it ... do... end
    it ... do... end
    # etc.
  end

  context 'first "foo" scenario' do
    let ...
    include_examples 'bar'
  end

  context 'second "foo" scenario' do
    let ...
    include_examples 'bar'
  end
end

目的是提供一组单一的共享示例,这些示例在多个操作上下文中进行了良好的覆盖,所有示例都通过内部共享示例列表运行。

这个错误很简单但很微妙。由于我关闭了 RSpec 猴子补丁 (disable_monkey_patching!),因此我必须在顶层使用 RSpec.<foo>。但是在任何其他 RSpec 块中,使用 RSpec.<foo> 定义 RSpec 的顶级 :main 上下文中的实体。因此,第二组共享的“内部”示例没有在 'foo' 中定义,而是在顶级定义。一旦超过一个其他文件require_relative执行了上述代码,这足以使事情变得混乱,足以触发 RSpec 警告。

解决方法是在嵌套集中只执行 shared_examples 'bar',而不是 RSpec.shared_examples 'bar',以便在内部上下文中正确描述内部示例。

(旁白:这是一个有趣的例子,说明关闭猴子补丁比乍一看更重要 - 这不仅仅是为了名称空间的纯度。它允许在声明之间进行更清晰的区分“这是顶级”和“这是嵌套的”。)