Brian Underwood
Brian Underwood

Reputation: 10856

Simplifying rspec unit tests

A lot of times in unit test in rspec having to specify both a context and a let is somewhat cumbersome and seems unnecessary. For example:

context 'type = :invalid' do
  let(:type) { :invalid }

  it { expect { subject }.to raise_error(ArgumentError) }
end

It would be nicer (in aggregate over lots of tests) if I could do something like:

let_context type: :invalid do
  it { expect { subject }.to raise_error(ArgumentError) }
end

The method would define a context and let(s) for me and the context's argument would be something like type = :invalid or let(:type) { :invalid } because I don't have anything else to say other that the fact that this variable has changed.

Upvotes: 1

Views: 259

Answers (2)

sshaw
sshaw

Reputation: 1014

A lot of times in unit test in rspec having to specify both a context and a let is somewhat cumbersome

Sounds like you might want to use a RSpec shared context.

UPDATE

RSpec provides a DSL for the syntax you're suggesting: a shared example. For example:

RSpec.shared_examples "some thang" do |type|
 it { expect { subject }.to raise_error(ArgumentError) }
end

RSpec.shared_examples "a thang" do
  include_examples "some thang", :invalid
  # Or whatever is more appropriate for your domain
  # I.e., If you're testing subclass behavior use it_should_behave_like()
end

Upvotes: 1

fl00r
fl00r

Reputation: 83680

actually you could get less lines by following some http://betterspecs.org recommendations:

context 'type = :invalid' do
  let(:type) { :invalid }
  it { expect{ subject }.to raise_error(ArgumentError)
end

Your variant could be read as

it raises an error expect subject to raise error

While this is much cleaner

it expect subject to raise_error

Nevertheless it is pretty off topic :)

UPD

Oh. Really you can't pass two blocks to method, so below example is not valid Ruby :)

context(:type) { :invalid } do
  it{ expect{ subject }.to raise_error(ArgumentError)
end

While your example

let_context type: :invalid do
  ...
end

Won't do lazy execution, like let does

Upvotes: 0

Related Questions