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)