DEV Community

loading...
Cover image for RSpec(Pt. 1): Getting Started

RSpec(Pt. 1): Getting Started

Ethan Gustafson
`${Frontend Developer}`
Updated on ・5 min read

This post won't go in depth on writing RSpec tests, but it will show you how to configure a .rspec file and how to use RSpec syntax with an example for a single Ruby class at the bottom.

Configuration

  • Ruby 2.0 or higher recommended
  • You must use RSpec version 3 or higher. Version 2 & 3 of RSpec are not interchangeable.
  • Install RSpec with gem install rspec

To write a simple RSpec test for a Ruby class, you can start by cd into your project directory and in the terminal run rspec --init, which will create two things for you.

  1. A new directory named 'spec' which contains a file named spec_helper.rb
  2. A new .rspec file in the root of the project directory.

.rspec files contain the configuration setting for testing with RSpec. You can see all of the options with rspec --help.

Here are a few things you can write in the .rspec file to configure rspec:

  1. --no-color, --color (--color Shows green output for passing tests, red for failing tests)
  2. --format progress, --format documentation (--format progress will show your test examples like this in the terminal: "....F.." - Dots are passing, F is failed. --format documentation will instead of showing dots and f's, will instead show the example descriptions of your tests in a green(passing) or red(failing) color.
  3. --no-profile, --profile (This one will determine whether or not RSpec shows you your fastest and slowest tests)
  4. --no-fail-fast, --fail-fast (--no-fail-fast will run all tests, --fail-fast will only output the first test that fails if any)
  5. --order defined, --order random (This one will either run the tests you have written in the order they are defined or at random)

If you create a .rspec file in your computers user directory, you can configure RSpec globally there and the rest of your projects will use that configuration.

If you use a .rspec file in the project directory, it will override any global .rspec configurations for that project.

I have a Ruby class called Character, which is loading a module that I am using for another class.

require_relative '../modules/instance_methods.rb'
class Character
    include InstanceMethods

    @@all = []

    def self.all
        @@all
    end

end
Enter fullscreen mode Exit fullscreen mode

Here is the module:

module InstanceMethods

    attr_accessor(:name, :bio, :url, :start_i, :end_i)

    def initialize(name, url)
        @name = name
        @url = url
        self.class.all << self
    end

end
Enter fullscreen mode Exit fullscreen mode

Create a spec test for your class with the class name at the front, for example my spec file name is character_spec.rb. In order to test the class from the spec file, you need to load the class code. At the top of your new spec file, require the file in which you are testing.

At the top of my spec file is:

require_relative '../lib/classes/character.rb'
Enter fullscreen mode Exit fullscreen mode

There is a syntax RSpec uses to define tests.

1) The Example Group

describe Character do
# Example Cases go here
end
Enter fullscreen mode Exit fullscreen mode

RSpec uses the describe keyword which takes a string or class name argument followed by do and end to define an Example Group. Above I used a class name, but it could also be 'Character'.

You can have two example groups inside of each other, in which case you can either use describe or context inside of the first example group because they are the same thing.

For example, you could set the first describe for the Character class, and the second nested describe for testing the attributes of the class.

Everything between that do and end belongs to the thing we want to test. In the code above, it is a class, so we are setting the Example Group to test the Character class.

2) Example Cases

describe Character do

   it "Instantiate with a name & URL" do
    #Expectations
   end
end
Enter fullscreen mode Exit fullscreen mode

The keyword it followed by a string argument with do and end defines an Example Case. You can also use the synonym for it which is specify. This is where you will house the actual test, the expectation. The string is what is outputted to you when you are testing your file just so you can see which test it is.

3) Expectations

it "Instantiate with a name & URL" do
    @character = Character.new("Luffy", "https://onepiece.fandom.com/wiki/Monkey_D._Luffy")
    expect(@character).to have_attributes(:name => "Luffy", :url => "https://onepiece.fandom.com/wiki/Monkey_D._Luffy")
end
Enter fullscreen mode Exit fullscreen mode

This is where the actual test is. The syntax for expectations is as follows:

expect().to()
expect().not_to()
Enter fullscreen mode Exit fullscreen mode

expect will take an argument of the thing you want to test, you will call .to() on the end of expect(), then you will use something called a 'Matcher' as an argument to .to() to test the two. There are many matchers:

  • Observation matchers (How things change)
  • collection matchers (Hashes, Arrays, Strings)
  • numeric-comparison matchers (numbers)
  • truthiness matchers (true || false)
  • Composing Matchers (Matchers than can take other matchers as its argument)
  • Equivalence matchers (Ruby loose, value & object identity equality)
  • Predicate Matchers (Dynamic & Custom matchers)

You can go more in depth on the abundance of them here at:
Expectations & Matchers

To run your spec file, run in the terminal:
rspec path-to-file-name.

To easily do this, type rspec in the terminal with a space after it, drag and drop your spec file into the terminal and it will give the entire path to your file.

For example:

rspec /Users/user/Desktop/Flatiron/Projects/CLI/spec/character_spec.rb
Enter fullscreen mode Exit fullscreen mode

Or you can simply just run in the terminal:

rspec spec
Enter fullscreen mode Exit fullscreen mode

Which will run all tests in the spec directory.

Here is my finished spec for the Character class:

require_relative '../lib/classes/character.rb'

describe Character do

    context "attributes" do

        subject { Character.new("Luffy", "https://onepiece.fandom.com/wiki/Monkey_D._Luffy") } 

        it "Instantiate with a name & URL" do
            expect(subject).to have_attributes(:name => "Luffy", :url => "https://onepiece.fandom.com/wiki/Monkey_D._Luffy")
        end

        it "Have attributes for :bio, :start_i, :end_i" do
            expect(subject).to respond_to(:bio, :start_i, :end_i)
        end

        it ":name, :url & :bio must be strings" do
            subject.bio = "Kaizoku-ō ni ore wa naru!"
            expect(subject.name).to be_an(String)
            expect(subject.url).to be_an(String)
            expect(subject.bio).to be_an(String)
        end

        it ":start_i and :end_i must be integers" do
            subject.start_i = 2
            subject.end_i = 4
            expect(subject.start_i).to be_an(Integer)
            expect(subject.end_i).to be_an(Integer)
        end

    end

    context 'class Methods' do
        it '.all method which will record all instances of the class' do
            expect(Character.all).to be_an(Array)
        end
    end

end
Enter fullscreen mode Exit fullscreen mode

And here is the output for when I run my spec tests:

Character
  attributes
    Instantiate with a name & URL
    Have attributes for :bio, :start_i, :end_i
    :name, :url & :bio must be strings
    :start_i and :end_i must be integers
  class Methods
    .all method which will record all instances of the class

Finished in 0.0073 seconds (files took 0.29535 seconds to load)
5 examples, 0 failures
Enter fullscreen mode Exit fullscreen mode

Discussion (0)