RSpec nested subjects
Tags: ruby, testing, rspec, tdd
Published: 2019-05-16 02:48:12

---
title: RSpec nested subjects
published: true
tags: ruby,testing,rspec,tdd
canonical_url: https://blog.chilcutt.com/2019/04/24/rspec-nested-subjects.html
---

The [RSpec subject functionality](https://relishapp.com/rspec/rspec-core/v/3-8/docs/subject/explicit-subject) 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.

<figure>
<img alt="programming" src="https://cdn-images-1.medium.com/max/12000/1*ofMfrqFMfpaTH_RMvI_RQA.jpeg"/>
<figcaption>
Photo by <a href="https://unsplash.com/photos/95YRwf6CNw8?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Clément H</a> on <a href="https://unsplash.com/search/photos/programming?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
</figcaption>
</figure>

---

The `subject` syntax allows you to use the [one-liner syntax](https://relishapp.com/rspec/rspec-core/v/3-8/docs/subject/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:

```ruby
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`:

```ruby
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.

<figure>
  <img
    alt="failures"
    src="https://cdn-images-1.medium.com/max/3624/1*8CMdd5YkCsObQJMDTy9B_A.png"/>
  <figcaption>Failures look slightly different, but make the same point.</figcaption>
</figure>

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:

```ruby
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:

```ruby
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:

```ruby
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](https://twitter.com/zackmariscal) for helping me edit and improve this post and my writing in general.*