DEV Community

SakuraMilkTea
SakuraMilkTea

Posted on • Edited on

Interesting Things I learned Writing Rspec Tests

Image description

Writing test code is good form and is obviously always recommended. Writing GOOD test is an excellent way to fool-proof the code you (I) have so far, but like everything else, it takes practice!

In an attempt to keep it fresh in my mind, here are a few things I found out recently about writing rspec code...

  • travel_to is useful... But only allowed once.

Okay. That was a bit dramatic. You can actually use travel_to in separate blocks as much as you want.

context "first context" do
  travel_to("2024-12-25") do
    expect(presents)
  end
end

context "second context" do
  travel_to("2024-12-31") do
    expect(fireworks)
  end
end
Enter fullscreen mode Exit fullscreen mode

However, you're (I am) not allowed to do some magical shenanigans such as this

context "first context" do
  travel_to("2024-12-25") do
    expect(presents)

    travel_to("2024-12-31") do
      expect(fireworks)
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Not only does it look weird and messy, but also you'll get a big angry error. So yeah.
However in some cases it will be inevitable for the whole file to be enclosed in a travel_to for some reason or other. And that's when it's a good idea to use travel_back!

context "first context" do
  travel_to("2024-12-25") do
    expect(presents)

  context "second context" do
    before do
      travel_back
    end
    travel_to("2024-12-31") do
      expect(fireworks)
    end
  end
  end
end
Enter fullscreen mode Exit fullscreen mode

Simple? Yes. But does it do a good job? Also yes.

Update: I have learned an even better method today. The trick is simply to not make subsequent travel_to into blocks!

context "first context" do
  travel_to("2024-12-25") do
    expect(presents)

    travel_to("2024-12-31")
    expect(fireworks)
  end
end
Enter fullscreen mode Exit fullscreen mode
  • It's better to not write DSLs dynamically

This one might come as a surprise for some, because it sure did for me. Consider this example

describe 'some spec' do
  (1..7).each do |n|
    let!(:"user_#{n}") { create(:user, name: "user#{n}") } 
  end
  # ...
end
Enter fullscreen mode Exit fullscreen mode

I thought I was super clever to use iteration like that, but learned from reviewers that it's not good practice. Although it saves time and works fine, it's not reader-friendly.
Instead, a very similar approach can be used through FactoryBot

describe 'some spec' do
  let!(:users) { FactoryBot.create_list(:user, 7) } 
  # ...
end
Enter fullscreen mode Exit fullscreen mode

This obviously assumes that the name is set in the FactoryBot file

FactoryBot.define do
  factory :user do
    sequence(:name) { |n| "user#{n}" }
    # ...
  end
end
Enter fullscreen mode Exit fullscreen mode

As I become more acquainted with rspec and keep writing more code, I might come back and edit this document with more interesting finds ☺︎

Let's keep doing our best!

Top comments (0)