RSpec fundamentals: setup, naming and basic structure

When you start programming, it’s not easy to know what to test, how to test, and why should you test? You’ve probably heard that TDD (as in Test Driven Development) is THE best practice. But at first, it’s hard to know what your code should do before you’re writing it.

Testing requires practice to reveal its potential.

When I started programming, I’d copy other people’s tests because, well, I had to test, right? But after a while, my tests would uncover edge cases, potential bugs I’d overlooked.

So, I feel a series of short know-hows, know-whats and, know-whys, could be of some use to newcomers; brief essays explaining one aspect of testing with RSpec.

If this sounds fun to you, let’s start with the basics.

What is RSpec?

First, let’s begin with the obvious question: what is RSpec?

RSpec is a testing framework built in Ruby to test Ruby code. It focuses on testing the behavior of your program: what am I feeding my code? What do I expect to come out?

It’s one of several testing frameworks available out there. You might also know Minitest.

Adding RSpec to your application

The RSpec team maintains a gem, making it easy to use the framework in Rails applications.

First, add RSpec to your Gemfile.

  # Gemfile

  gem "rspec-rails", group: [:development, :test]

Install the gem.

  bundle install

Scaffold RSpec’s configuration and switch your application’s testing framework to RSpec.

  rails generate rspec:install

Now, run your migrations and prepare your test database.

  rails db:migrate && rails db:test:prepare

There! Now, you can run your tests by typing rspec spec in your shell. spec is the folder where you’ll create your test files.

Naming your RSpec files

RSpec naming convention is straightforward:

Architecturing your spec folder

To make sure RSpec and Rails work smoothly together, mimick the structure of your `app` folder.

  my_app_directory
  |
  |- app
  |  |
  |  |- models
  |     |
  |     |- user.rb
  |
  |- spec
     |
     |- models
        |
        |- user_spec.rb

There’s only one catch:

So for testing controllers, your folder’s structure is:

  my_app_directory
  |
  |- app
  |  |
  |  |- controllers
  |     |
  |     |- users_controller.rb
  |
  |- spec
     |
     |- controllers ❌
     |
     |- requests
        |
        |- users_controller_spec.rb

The structure of your RSpec files

Let’s say we want to test our User model. Our file’s structure would look like this:

  # spec/models/user_spec.rb

  require 'rails_helper'

  RSpec.describe User do
    # test stuff
  end

There! Your setup is done.

But now, I’d like us to dig into each element so we get a better understanding of what’s going on.

The code below is from the RSpec repository.

  def self.expose_example_group_alias(name)
    return if example_group_aliases.include?(name)

    example_group_aliases << name

    (class << RSpec; self; end).__send__(:define_method, name) do |*args, &example_group_block|
      group = RSpec::Core::ExampleGroup.__send__(name, *args, &example_group_block)
      RSpec.world.record(group)
      group
    end

    expose_example_group_alias_globally(name) if exposed_globally?
  end

It’s a bit hard to read because of the metaprogramming bits, but the main idea is that it defines the .describe instance method in the RSpec::Core::ExampleGroup class with the abstraction you’re testing (User) and the tests you wrote as arguments.

I hope these explanations will give you a better understanding of how RSpec works. Next time, we’ll write our first tests.

Noticed something? Ping me on Twitter or create an issue on GitHub.

Cheers,

Rémi

  1. Thanks @Benoit for pointing that out!