Какая разница между "include_examples" и "it_behaves_like"?
В RSpec, какая разница между it_behaves_like
и include_examples
?
В документации говорится:
include_examples
- включить (-ы) примеры в текущем контексте
it_behaves_like "name"
- включить (-ы) примеры во вложенном контексте
Но что это значит? Замена одного на другой, похоже, не влияет на то, проходят ли мои тесты или не проходят. Есть ли причина предпочесть друг другу в некоторых ситуациях?
Также есть it_should_behave_like
и it_behaves_like
только синонимы?
Ответы
Ответ 1
Вероятно, вы знаете, как использовать describe
, context
, it
и specify
, чтобы четко передать один аспект вашего кода. Вложенный контекст, предоставляемый it_behaves_like
, может использоваться для улучшения этой связи с читателем.
Я опишу свой пример на примере, приведенном в документации RSpec для общих примеров:
shared_examples "a collection" do
context "initialized with 3 items" do
it "says it has three items" do
# ...
end
end
end
describe Array do
it_behaves_like "a collection"
include_examples "a collection"
end
Если вы запустите RSpec с помощью --format documentation
, вы получите следующий вывод:
Array
behaves like a collection
initialized with 3 items
says it has three items
initialized with 3 items
says it has three items
Таким образом, разница в том, как считывается спецификация, например, в случае сбоя.
Какой стиль вы предпочитаете - это вопрос эстетики того, как вам нравятся ваши спецификации. Кроме того, вы бы предложили всегда использовать один и тот же стиль, если вы работаете в команде, чтобы улучшить согласованность.
Кроме того, являются ли это_should_behave_like и it_behaves_like только синонимами?
Почти, контекст назван по-разному. it should behave like ...
vs behaves like ...
. Опять вопрос об эстетике.
Ответ 2
Там есть разница в том, что вы передаете параметры в shared_examples.
Он очень хорошо объяснил предупреждение в своем документе:
ПРЕДУПРЕЖДЕНИЕ. Когда вы включаете параметризованные примеры в текущем контексте несколько раз, вы можете переопределить предыдущие определения методов и последние победы в объявлении. Поэтому, если у вас есть такой общий пример (или общий контекст)
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
Чтобы предотвратить такую тонкую ошибку, выдается предупреждение, если вы объявить несколько методов с тем же именем в одном контексте. Если вы получите это предупреждение, самое простое решение - заменить include_examples с it_behaves_like, таким образом, метод переопределения исключается из-за вложенного контекста, созданного it_behaves_like