Introduction to RSpec shared examples
As a Ruby developer, I often implement classes with inheritance or modules (and concerns in the case of Rails) to implement shared logic. We need to test each extension to make sure that it behaves as we intend it to, and when doing so, RSpec shared examples to help us keep the testing DRY.
Creating shared examples
We can define shared examples within an RSpec file (if it is only used in the particular RSpec test, or a general location loaded by RSpec. Here will use the shared_examples
method to define a shared example and include_examples
method to include it.
# ./spec/support/shared_examples/acts_as_inbound_webhook_endpoint.rb
shared_examples 'acts as an inbound webhook endpoint' do |action = :create|
subject { post :create, body: data.to_json }
let(:data) { { 'foo' => 'bar' } }
it 'records the inbound webhook' do
expect { subject }.to change(InboundWebhook, :count).by(1)
webhook = InboundWebhook.recent.first
expect(webhook.body).to eq(data)
end
end
Then we can use them in the code as follows:
include_examples 'acts as an inbound webhook endpoint'
Customisng shared examples
It is in the natue of any thing shared that you eventually need some sort of customization. In the case of shared examples, RSpec allows us to pass in arguments to the shared example block.
Accepting Arguments
shared_examples 'acts as an inbound webhook endpoint' do |action = :create|
subject { post action, body: data.to_json }
let(:data) { { 'foo' => 'bar' } }
it 'records the inbound webhook' do
expect { subject }.to change(InboundWebhook, :count).by(1)
webhook = InboundWebhook.recent.first
expect(webhook.body).to eq(data)
end
end
Then we can use them in the code as follows:
include_examples 'acts as an inbound webhook endpoint', :update
Overriding let
definitions
Another way we can override RSpec shared examples is by means of overriding let
definitions by introducing a block when using include_examples
. Using the above example, should we need to override let(:data)
, we could:
include_examples 'acts as an inbound webhook endpoint' do
let(:data) { { 'bar' => 'baz' } }
end
About the Author
Ziyan Junaideen -
Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.