使用共享示例
共享示例允许您描述类或模块的行为。声明时,共享组的内容将被存储。它只在另一个示例组的上下文中实现,该示例组提供了共享组运行所需的任何上下文。
共享组使用以下任何一种方法包含在另一个组中:
include_examples "name" # include the examples in the current context
it_behaves_like "name" # include the examples in a nested context
it_should_behave_like "name" # include the examples in a nested context
matching metadata # include the examples in the current context
警告: 包含共享组的文件必须在使用它们的.rb 文件之前加载。虽然有一些约定来处理这个问题,但 RSpec 没有做任何特别的事情(比如自动加载)。这样做需要一个严格的文件命名约定,这会破坏现有的套件。
警告: 当您在当前上下文中多次包含参数化的示例时,您可能会覆盖以前的.rb 方法定义,并且最后一个声明获胜。所以,如果你有这种共享示例(或共享上下文)
RSpec.shared_examples "some example" do |parameter|
\# Same behavior is triggered also with either `def something; 'some value'; end`
\# or `define_method(:something) { 'some value' }`
let(:something) { parameter }
it "uses the given parameter" do
expect(something).to eq(parameter)
end
end
RSpec.describe SomeClass do
include_examples "some example", "parameter1"
include_examples "some example", "parameter2"
end
您实际上正在做的是(注意第一个示例将失败)
RSpec.describe SomeClass do
\# Reordered code for better understanding of what is happening
let(:something) { "parameter1" }
let(:something) { "parameter2" }
it "uses the given parameter" do
\# This example will fail because last let "wins"
expect(something).to eq("parameter1")
end
it "uses the given parameter" do
expect(something).to eq("parameter2")
end
end
为了防止这种细微的错误,如果您在同一个上下文中声明了多个具有相同名称的方法,将发出警告。如果您收到此警告,最简单的解决方案是用`it_behaves_like` 替换`include_examples`,这样可以避免方法覆盖,因为`it_behaves_like` 创建了嵌套上下文
约定
最简单的方法是显式地从使用共享示例的文件中要求带有共享示例的文件。请记住,RSpec 将`spec` 目录添加到`LOAD_PATH` 中,因此您可以说`require 'shared_examples_for_widgets'` 以要求`#{PROJECT_ROOT}/spec/shared_examples_for_widgets.rb` 中的文件。
一种约定是将包含共享示例的文件放在`spec/support/` 中,并从`spec/spec_helper.rb` 中要求该目录中的文件。
Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
从历史上看,这包含在`rspec-rails` 中生成的`spec/spec_helper.rb` 文件中。但是,为了降低测试套件的启动时间,最好不要自动要求目录中的所有文件。当只运行一个规范文件时,加载不必要的依赖项或执行不必要的设置会对第一个示例运行之前需要多长时间产生显著影响。
当所有包含共享组的组都位于同一个文件中时,只需在该文件中声明共享组即可。
在一个文件中包含在两个组中的共享示例组
假设 一个名为“collection_spec.rb”的文件包含
require "set"
RSpec.shared_examples "a collection" do
let(:collection) { described_class.new([7, 2, 4]) }
context "initialized with 3 items" do
it "says it has three items" do
expect(collection.size).to eq(3)
end
end
describe "#include?" do
context "with an item that is in the collection" do
it "returns true" do
expect(collection.include?(7)).to be(true)
end
end
context "with an item that is not in the collection" do
it "returns false" do
expect(collection.include?(9)).to be(false)
end
end
end
end
RSpec.describe Array do
it_behaves_like "a collection"
end
RSpec.describe Set do
it_behaves_like "a collection"
end
当 我运行`rspec collection_spec.rb --format documentation` 时
那么 示例应该全部通过
并且 输出应该包含
Array
behaves like a collection
initialized with 3 items
says it has three items
#include?
with an item that is in the collection
returns true
with an item that is not in the collection
returns false
Set
behaves like a collection
initialized with 3 items
says it has three items
#include?
with an item that is in the collection
returns true
with an item that is not in the collection
returns false
使用块为共享组提供上下文
假设 一个名为“shared_example_group_spec.rb”的文件包含
require "set"
RSpec.shared_examples "a collection object" do
describe "<<" do
it "adds objects to the end of the collection" do
collection << 1
collection << 2
expect(collection.to_a).to match_array([1, 2])
end
end
end
RSpec.describe Array do
it_behaves_like "a collection object" do
let(:collection) { Array.new }
end
end
RSpec.describe Set do
it_behaves_like "a collection object" do
let(:collection) { Set.new }
end
end
当 我运行`rspec shared_example_group_spec.rb --format documentation` 时
那么 示例应该全部通过
并且 输出应该包含
Array
behaves like a collection object
<<
adds objects to the end of the collection
Set
behaves like a collection object
<<
adds objects to the end of the collection
将参数传递给共享示例组
假设 一个名为“shared_example_group_params_spec.rb”的文件包含
RSpec.shared_examples "a measurable object" do |measurement, measurement_methods|
measurement_methods.each do |measurement_method|
it "should return #{measurement} from ##{measurement_method}" do
expect(subject.send(measurement_method)).to eq(measurement)
end
end
end
RSpec.describe Array, "with 3 items" do
subject { [1, 2, 3] }
it_should_behave_like "a measurable object", 3, [:size, :length]
end
RSpec.describe String, "of 6 characters" do
subject { "FooBar" }
it_should_behave_like "a measurable object", 6, [:size, :length]
end
当 我运行`rspec shared_example_group_params_spec.rb --format documentation` 时
那么 示例应该全部通过
并且 输出应该包含
Array with 3 items
it should behave like a measurable object
should return 3 from #size
should return 3 from #length
String of 6 characters
it should behave like a measurable object
should return 6 from #size
should return 6 from #length
将`it_should_behave_like` 设为`it_has_behavior` 的别名
假设 一个名为“shared_example_group_spec.rb”的文件包含
RSpec.configure do |c|
c.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:'
end
RSpec.shared_examples 'sortability' do
it 'responds to <=>' do
expect(sortable).to respond_to(:<=>)
end
end
RSpec.describe String do
it_has_behavior 'sortability' do
let(:sortable) { 'sample string' }
end
end
当 我运行`rspec shared_example_group_spec.rb --format documentation` 时
那么 示例应该全部通过
并且 输出应该包含
String
has behavior: sortability
responds to <=>
共享元数据自动包含共享示例组
假设 一个名为“shared_example_metadata_spec.rb”的文件包含
RSpec.shared_examples "shared stuff", :a => :b do
it 'runs wherever the metadata is shared' do
end
end
RSpec.describe String, :a => :b do
end
当 我运行`rspec shared_example_metadata_spec.rb` 时
那么 输出应该包含
1 example, 0 failures
共享示例可以按上下文嵌套
假设 一个名为“context_specific_examples_spec.rb”的文件包含
RSpec.describe "shared examples" do
context "per context" do
shared_examples "shared examples are nestable" do
specify { expect(true).to eq true }
end
it_behaves_like "shared examples are nestable"
end
end
当 我运行`rspec context_specific_examples_spec.rb` 时
那么 输出应该包含
1 example, 0 failures
共享示例可以从子级上下文访问
假设 一个名为“context_specific_examples_spec.rb”的文件包含
RSpec.describe "shared examples" do
shared_examples "shared examples are nestable" do
specify { expect(true).to eq true }
end
context "per context" do
it_behaves_like "shared examples are nestable"
end
end
当 我运行`rspec context_specific_examples_spec.rb` 时
那么 输出应该包含
1 example, 0 failures
并且 输出不应该包含
Accessing shared_examples defined across contexts is deprecated
共享示例在每个上下文中都是隔离的
假设 一个名为“isolated_shared_examples_spec.rb”的文件包含
RSpec.describe "shared examples" do
context do
shared_examples "shared examples are isolated" do
specify { expect(true).to eq true }
end
end
context do
it_behaves_like "shared examples are isolated"
end
end
当 我运行`rspec isolated_shared_examples_spec.rb` 时
那么 输出应该包含
Could not find shared examples \"shared examples are isolated\"