DEV Community

loading...
Cover image for Testing 1, 2, 3... RSpec Basics and Tips for RoR.

Testing 1, 2, 3... RSpec Basics and Tips for RoR.

Desiree Lerma
Software Engineer. Learning something new everyday!
・3 min read

I have recently begun my dive into the job search pool and have landed a couple of interviews. Exciting, right?! In each interview I have been asked about testing. Whether it was in regards to my preference in testing or actually having to implement my own tests for a challenge, the subject came up. That's when I realized, my way of testing an application (which had been by running my server and testing pieces manually) would not be the best route when in the real software engineering world and dealing with much LARGER applications. Now don't get me wrong, I have definitely read tests before, I've just never really written them out myself until I had a code challenge which asked for such to be done. So I thought it would be a great idea to take a dive into some basic keywords to read and write tests as well as compile a small cheatsheet of RSpec matchers.

First and foremost, you want to ensure you have the rspec gem in your gem file and run bundle install. You may also generate boilerplate files with the rails generate command.

gem 'rspec-rails', '~> 5.0.0'

rails g rspec:install
Enter fullscreen mode Exit fullscreen mode

Next, we'll need to require any and all files we want to include in the specific test file we're working in.
If you use scaffold to generate your files, your tests will automatically require 'rails_helper'.

require 'main/tester.rb'
Enter fullscreen mode Exit fullscreen mode

Now the fun stuff. Actually writing tests!

To have a skeleton of a test, create a describe block. The describe keyword tells RSpec which class and/or string argument you want to test as well as allow you to group tests for that class/argument together. Within your describe block you will also have an it block which will define a test/test case. Like describe, it accepts class names and string arguments (describe what behavior should happen inside the block). Another important keyword is expect which is a verification step to ensure the condition we expected has been met.

describe Tester do
  it "does something" do
   test = Tester.new
   expect(test.name).to eq("something")
  end
end
Enter fullscreen mode Exit fullscreen mode

Let

Alright, let's get down to business! (Extra cool points if you understood that reference) RSpec has a let method which allows you to reuse objects for many tests. The let method is essentially creating a variable to be used throughout the specific test file.

let(:valid_attributes) {
# here you will add a hash of your valid attributes
  {
  first_attr: "your first value",
  second_attr: "make sure it's the correct datatype",
  another_attr: true,
  and_so_on: 2
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, if you need to create an object throughout, you can simply write Tester.create valid_attributes in your describe block.

Subject

Another version of let is the subject keyword where you can only have one subject (an instance) of the object you're testing.

describe "running a test with subject" do 
  subject { Tester.new }
  # or subject (:first_test) { Tester.new }
  it "was saved successfully" do
    expect(subject).to be_an(Tester)
    # or expect(first_test).to be_an(Tester)
  end
end
Enter fullscreen mode Exit fullscreen mode

The subject keyword is normally used to test ActiveRecord validations with shoulda matchers.

Context

If you find yourself wanting or needing to test different scenarios within your application context is the tool for you. With the context keyword you can describe different possibilities to be tested within that file.

describe Tester do
  context "when user is a dog owner" do
    it "displays some dog info"
    end

    it "displays dog toy info" do
    end
  end

  context "when user is a cat owner" do
    it "displays some cat info"
    end

    it "displays cat toy info" do
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Now that I've reviewed the basics of creating your own RSpec tests and what the keywords mean and do, I'll provide you with a small cheatsheet of matchers I've compiled.

.to eq
.not_to be
.to be_success
.to have_http_status
.to be_a_new
.to be_an
.to be_a
.to render_template
.to route_to
.to redirect_to
.to be_redirect
.to be_routable
.to be_nil
.to start_with
.to be_between
.to end_with
.to have_attributes
.to raise_error
.to change
.to be_instance_of
Enter fullscreen mode Exit fullscreen mode

I hope this blog helps you understand how to read and write RSpec tests a tad more. I know writing it certainly helped me!

Resources:

Discussion (9)

Collapse
sturpin profile image
Sergio Turpín • Edited

I take note! 😊
Sorry for my ignorance, do you think that with minitest (github.com/seattlerb/minitest) you can do the same tests as with Rspec?

I know it's bad practice... but I never wrote a test in my application and now that I have seen your article, you have aroused my curiosity 😄

Collapse
djuber profile image
Daniel Uber • Edited

Hi Sergio,

I think yes, you can use minitest (rails does this for its internal tests, via ActiveSupport::TestCase ) and ruby supports this as part of the stdlib in Test::Unit::TestCase . There are gems to bring a lot of the "expectation" DSL from RSpec into Minitest.

A lot of application developers (the team behind DEV included) use RSpec, but there's certainly nothing requiring you to use RSpec with a rails app. There's a lot of community mindshare around RSpec, but there are always dissenting opinions (people coming from xUnit style testing frameworks in other languages find parts of minitest less weird, people trying to limit complexity prefer the equivalence of a unit test with the code that calls it, some people are really upset about the use of nested contexts and overriden let declarations). If you already have experience with Minitest, and aren't also working with a team of RSpec advocates or experts, use what works best for you. If you're trying to capture some of the "nice to have" features RSpec adds, there are usually gems, but you might have to do a little extra reading or extra configuration to figure things out. This might include the expect syntax and some of the collection matchers.

A little dated (it's talking about Rails 4), but blowmage.com/2013/07/08/minitest-s... might be a helpful read to get your bearings.

Collapse
sturpin profile image
Sergio Turpín

Hi Daniel,

Thank you so much!! 😊 Your explanation has been excellent. I generally work alone and wanted to start doing simple unit tests and I honestly didn't know where to start 😅.

If you had to start, which one would you start with?

Thread Thread
djuber profile image
Daniel Uber

I am personally comfortable with RSpec so I would reach for it by default in a personal project, however starting with either should be fine. The easy answer is "find the testing tutorial for your framework, and use it until you have a reason to change".

For rails that's probably the testing guide. The available assertions section probably gives you a "vocabulary" list to get started and suggest what you can test out of the box. The guide for rails is written for Minitest. RSpec's documentation also has details on how to integrate with rails projects (and there are going to be lots of examples available on github for both setups).

Usually, once you've got the first test running (it can find your code, it can load a class and call its methods) the rest is easy, and your problems may center more on making testable code (so the tests are easier to write) than configuring your test framework.

Thread Thread
sturpin profile image
Sergio Turpín

Thank you very much for your opinion, it's very helpful 😃

Collapse
djuber profile image
Daniel Uber • Edited

I would add to the list of resources you included the rspec docs themselves, which are written in a BDD style, it's "given some file with code as shown", "when I run this command", "the output looks like this" which is super useful in formalizing what the documentation is trying to say, by showing what it's saying, too.

relishapp.com/rspec/rspec-core/v/3... is a concrete example.

For me, the hardest part of using the documentation is figuring out which of the bundled gems provide the functionality I need, since the documentation is divided between the gems, but I am usually internally thinking "this is rspec" about the combination of all of the components, and I find myself always second guessing "is this a mock from rspec-mocks? or is this an expectation from rspec-expectations? or is this a rails specific helper in rspec-rails?"

Collapse
desilerma25 profile image
Desiree Lerma Author

Hi Daniel!
Thank you for the feedback and the additional resource. I'll add it to the resources I currently have listed. I agree, sifting through the gems to find the correct one is also a difficulty for me.

Collapse
gusandrioli profile image
Gustavo Andrioli

Great stuff, thank you for this

Collapse
nmhummel profile image
Natalie Hummel

Bookmarked for when I am ready to incorporate testing in my projects!