Testing Your Ruby Code With RSpec

Shreya Sridhar
4 min readDec 22, 2020

Testing frameworks are used extensively in Agile teams, both by technical developers [and by product and software managers].

Test Driven Development (TDD) is a testing methodology that relies on repetition of a short development cycle. The developer begins by writing a failed test and then implements a solution to pass the test case. The test cases are refactored as needed and development continues.

Behavior Driven Development(BDD), on the other hand, is an extension of a TDD in a natural language that is readable by even non-technical stakeholders. It focuses more on feature specific development. A BDD tests functionality from a user’s standpoint. BDD principles are being increasingly adopted because of the thinning line between technical jargon and tangible business outcomes.

RSpec is a popular Ruby gem that encapsulates these dual functionalities.

Installation

gem install rspec

RSpec Keywords & Matchers

a. Describe : denotes the collection of tests that follows. It can take a class name or string argument

b. It : describes what specific behaviour should happen in the ‘it’ block

c. Expect : used to define an expectation (just like normal English!)

Below are additional RSpec’s built-in matchers that can used:

  1. Equivalence :

expect(actual).to eq(expected) # passes if actual == expected
expect(actual).to eql(expected) # passes if actual.eql?(expected)
expect(actual).not_to eql(not_expected) # passes if not(actual.eql?(expected))

2. Identity

expect(actual).to be(expected) # passes if actual.equal?(expected)
expect(actual).to equal(expected) # passes if actual.equal?(expected)

3. Comparisons

expect(actual).to be > expected
expect(actual).to be >= expected
expect(actual).to be <= expected
expect(actual).to be < expected
expect(actual).to be_within(delta).of(expected)

4. Regular

expect(actual).to match(/expression/)

5. Expecting Errors

expect { ... }.to raise_error
expect { ... }.to raise_error(ErrorClass)
expect { ... }.to raise_error("message")
expect { ... }.to raise_error(ErrorClass, "message")

6. Compound Matchers

You can also create compound matcher expressions using and or or:

expect(elephant).to start_with("e").and end_with("t")
expect(rainbow).to eq("red").or eq("green").or eq("yellow")

Example 1 : RSpec code for a method that returns the reverse of a number

The 2 ‘it’ methods below define 2 different user input cases for the method reverse_num. We create variables to store our expected outputs from the method and compare against expected values. Describe encapsulates a group logic for the reverse_num method to work satisfactorily.

Test Doubles & Stubs

RSpec doubles/mocks are used as dummy placeholders for other objects. RSpec doubles allow the developer to test code which contains classes that may not even exist and helps reduce the scope of any errors to the class in question and not any other class. RSpec stub is used as a dummy placeholder for existing methods or method that do not exist yet.

Example 2 : RSpec code to check to see if an Album class’s album_song method returns a list of songs.

Songs 1 & 2 are test doubles for the Song class and the method name is assigned using a stub.

describe Album do 
it 'the list_student_names method should work correctly' do
song1 = double('song')
song2 = double('song')

song1.stub(:name).and_return('Here comes the sun')
song2.stub(:name).and_return('Let it be')

a= Album.new [song1,song2]
expect(a.album_songs).to eq('Here comes the sun','Let it be')
end
end

Subjects

Object Instantiation may be included in the describe line to make the code crisp and readable.

Example 4: RSpec code the check attributes using Subjects

describe Song.new 'Let it Be', 'The Beatles' do 
it { is_expected.to have_attributes(song_name: 'Let it Be') }
it { is_expected.to have_attributes(band_name: 'The Beatles') }
end

Example 3:

RSpec comes very handy when using Rails MVC frameworks too!

Consider an MVC model with Artists and Songs where each artist can have many songs and each song belongs to one artist.

Model tests can be written as shown below (tests if .top_hit returns most liked song):

Controller method tests can be written similar to feature tests. Controller CRUD method tests may be written as shown below (tests if GET index renders index and shows index/html):

Improving Efficiency Using RSpec

Running your ruby code as follows : ruby run.rb — profile , helps the developer understand which tests take longer and helps prioritize them.

References : https://relishapp.com/rspec, https://www.rubyguides.com/2018/07/rspec-tutorial/ , https://rubydoc.info/gems/rspec-expectations/frames

--

--