DEV Community

Kyle Chilcutt
Kyle Chilcutt

Posted on • Originally published at blog.chilcutt.com on

RSpec nested subjects

The RSpec subject functionality can be useful for simplifying your spec setup and getting straight to the point. I really like using an explicit subject because it helps describe what functionality is under test when you’re writing your specs. Recently, I learned it was possible to nest your subject when using a named subject.

programming

Photo by Clément H on Unsplash

The subject syntax allows you to use the one-liner syntax for writing a test which can really clean up a spec file. Let’s take a trivial example of a Rails model:

describe Car do let(:car) { Car.new } it "is a vehicle" do expect(car).to be_a(Vehicle) end end 

For this trivial case, you’ll notice that our expectation pretty literally matches the description of the test case. This might be a good use case for subject:

describe Car do subject { Car.new } it { is_expected.to be_a(Vehicle) } end 

The above will test the same functionality and also leave pretty similar spec output when the spec is run.

failures


Failures look slightly different, but make the same point.

You can also redefine your subject for different blocks of your test. Let’s set the subject for an instance method that I want to test:

describe Car do subject { Car.new } it { is_expected.to be_a(Vehicle) } describe "#parked?" do subject { Car.new.parked? } it { is_expected.to eq(false) } end end 

Dope. By redefining the subject we can use the one-line syntax wherever we want.

The final trick is we can add an name to our initial subject so we can reference it later within the spec:

describe Car do subject(:car) { Car.new } it { is_expected.to be_a(Vehicle) } describe "#parked?" do subject { car.parked? } it { is_expected.to eq(false) } end end 

I find this particularly useful if the subject in the enclosing block has some complex setup:

describe Car do let(:driver) { Person.new } let(:front_seat) { Person.new } subject(:car) { Car.new(driver: driver, front_seat: front_seat) } it { is_expected.to be_a(Vehicle) } describe "#parked?" do subject { car.parked? } it { is_expected.to eq(false) } end end 

Now we can leverage any earlier setup while still having the benefits of different subjects in each context.


Shout out to Zack Mariscal for helping me edit and improve this post and my writing in general.

Top comments (0)