Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between "include_examples" and "it_behaves_like"?

Tags:

ruby

rspec

In RSpec, what's the difference between it_behaves_like and include_examples?

The documentation says:

include_examples — include(s) the examples in the current context

it_behaves_like "name" — include(s) the examples in a nested context

But what does this actually mean? Replacing one with the other doesn't seem to have an effect on whether my tests pass or fail. Is there a reason to prefer one over the other in some situations?

Also, are it_should_behave_like and it_behaves_like just synonyms?

like image 872
GMA Avatar asked Oct 24 '13 03:10

GMA


People also ask

What is context in RSpec?

According to the rspec source code, “context” is just a alias method of “describe”, meaning that there is no functional difference between these two methods. However, there is a contextual difference that'll help to make your tests more understandable by using both of them.

What is describe in RSpec?

The word describe is an RSpec keyword. It is used to define an “Example Group”. You can think of an “Example Group” as a collection of tests. The describe keyword can take a class name and/or string argument.

What is let in RSpec?

let generates a method whose return value is memoized after the first call. This is known as lazy loading because the value is not loaded into memory until the method is called. Here is an example of how let is used within an RSpec test. let will generate a method called thing which returns a new instance of Thing .

How do I download RSpec?

Installing RSpecBoot up your terminal and punch in gem install rspec to install RSpec. Once that's done, you can verify your version of RSpec with rspec --version , which will output the current version of each of the packaged gems. Take a minute also to hit rspec --help and look through the various options available.


2 Answers

You probably know how to use describe, context, it and specify to clearly communicate one aspect of your code. The nested context provided by it_behaves_like can be used to improve this communication with the reader.

I will base my example on the example given in the RSpec documentation for shared examples:

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 

If you run RSpec with --format documentation you get the following output:

Array   behaves like a collection     initialized with 3 items       says it has three items   initialized with 3 items     says it has three items 

So the difference is how the spec is read eg in case of a failure.

Which style you prefer is a question of aesthetics of how you like your specs to read. Furthermore you would suggest to always use the same style if you work in a team to improve consistency.


Also, are it_should_behave_like and it_behaves_like just synonyms?

Almost, the context is named differently. it should behave like ... vs behaves like .... Again a question of aesthetics.

like image 88
jayeff Avatar answered Sep 27 '22 18:09

jayeff


There is a difference in case you pass parameters to the shared_examples.

It's explained very well in a warning in their doc:

WARNING: When you include parameterized examples in the current context multiple times, you may override previous method definitions and last declaration wins. So if you have this kind of shared example (or shared context)

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 

You're actually doing this (notice that first example will fail):

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 

To prevent this kind of subtle error a warning is emitted if you declare multiple methods with the same name in the same context. Should you get this warning the simplest solution is to replace include_examples with it_behaves_like, in this way method overriding is avoided because of the nested context created by it_behaves_like

like image 33
rona Avatar answered Sep 27 '22 19:09

rona