Getting Started With Testing In Rails (Using Minitest and RSpec)

i am error

Everyone says testing is important, but it’s easy to put off learning about and implementing. When you want to get an app made, and then you want to get all its features working, it always seems like testing can be put off till later.

generic software testing image

Well later has arrived! It’s time I added some tests to my backend, and thanks to the excellent Rails documentation, it’s not too hard to do.

Ruby on Rails test folder

One of the many cool things about all Rails apps is that whenever you create a Rails app, Rails also creates a test directory within the app.

Rather than butcher what the documentation has to say, I’ll quote it verbatim:

The helpers, mailers, and models directories are meant to hold tests for view helpers, mailers, and models, respectively. The controllers directory is meant to hold tests for controllers, routes, and views. The integration directory is meant to hold tests for interactions between controllers.
The system test directory holds system tests, which are used for full browser testing of your application. System tests allow you to test your application the way your users experience it and help you test your JavaScript as well. System tests inherit from Capybara and perform in browser tests for your application.
Fixtures are a way of organizing test data; they reside in the fixtures directory.
A jobs directory will also be created when an associated test is first generated.
The test_helper.rb file holds the default configuration for your tests.
The application_system_test_case.rb holds the default configuration for your system tests.

Thanks Rails documentation!

1. Minitest

Minitest is the default testing library used by Rails.

Some takeaways from the documentation:

  • Every time you generate a Rails app, Rails creates a test directory for your app.
  • Every time you generate a model for your app, Rails creates tests stubs in the test directory.

For example, I have a User model, and the default test stub in my test/models/user_test.rb file looks like this:

class UserTest < ActiveSupport::TestCase
# test “the truth” do
# assert true
# end

Uncommenting the default test method and running rails test or rake in my Terminal should return true.

Unfortunately, my first test failed :(

rails test pic 1

My app has a table Stories, and also a table Genres, and Story has_many :genres, through: :plots, but my Stories table doesn’t have a column named “genre”, so why was I getting this ActiveRecord error?! My efforts to learn about testing were already giving me errors.

This lead to more than an hour of googling “ActiveRecord:: Fixture:: FixtureError: table foo has no column named bar” which lead me to many Rails Github issues pages and StackOverflow questions similar to my issue that didn’t solve my problem, and in the process I learned that if you do “loves”.singularize you get “lofe”, which is some fun Ruby trivia. Finally I landed on this StackOverflow page, which had this answer in bold:

Check fixtures and see if they are mis-matched to your schema.

Which lead me to the test/fixtures/stories.yml file, where indeed, I found this:

# Read about fixtures at
title: MyString
genre: MyString
content: MyString
user_id: MyString
title: MyString
genre: MyString
content: MyString
user_id: MyString

Fixtures are sample data, written in YAML, with one file per model.

I didn’t remember generating my Stories table with a genre value, but that must have been what happened way back when I first started this app. Another good reason to start apps with testing! Apps change over time, after all, and this is often where bugs come from.

Removing those two genre: MyString lines from that file and running the test again lead to a new error, involving a different relationship but easily solved like the first.

rails test pic 2

My database had changed, but my fixtures were reflecting a previous version of the schema instead of the current schema. I fixed the issue by deleting the unnecessary yml file.

Running rails test lead to yet another error. This was getting fun! How many errors would Rails throw my way before I could pass the default assert true truth test??

rails test pic 3

ActiveRecord::Fixture::FixtureError: table “genres” has no column named “horror”.

My genres.yml fixtures file looked like this:

horror: MyString
action: MyString
scifi: MyString
fantasy: MyString
comedy: MyString
drama: MyString
romance: MyString
western: MyString
family: MyString
random: MyString
horror: MyString
action: MyString
scifi: MyString
fantasy: MyString
comedy: MyString
drama: MyString
romance: MyString
western: MyString
family: MyString
random: MyString

Which was weird, cuz my create_genres migration file looks like this:

class CreateGenres < ActiveRecord::Migration[5.1]
def change
create_table :genres do |t|
t.string :name

I only add the different genres in my seeds file:

genres = Genre.create([
{ name: ‘horror’ },
{ name: ‘scifi’ },
{ name: ‘action’ },
{ name: ‘drama’ },
{ name: ‘fantasy’ },
{ name: ‘comedy’ },
{ name: ‘romance’ },
{ name: ‘western’ },
{ name: ‘family’ },
{ name: ‘random’ },
{ name: ‘user_generated’ },

I guess I originally added all those genres directly to the Genres table. It’d be cool if fixtures kept up with the schema, but it doesn’t.

To better reflect my schema, I changed my genres.yml file to this:

name: MyString
name: MyString

Which lead to a new error when I ran rails test:

rails test pic 4

ActiveRecord::Fixture::FixtureError: table “characters” has no column named “hero”.

Oh boy. Is anyone still reading this? Is this boring as fuck or what? Why am I live blogging my experience learning about Rails testing? Oh well, can’t stop now.

But I will skip ahead to say: I continued in this fashion, editing my fixture files to make them reflect my schema, until I saw:

rails test pic 5

1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

Yeah! Success! 1 runs, 1 assertions, 0 failures, 0 errors, 0 skips. What a wonderful feeling it is, to pass a test, especially when that test is testing “the truth”, and successfully asserting that the truth is true.


This was actually a good way to learn what the hell was going on in those fixture YAML files, and yet another motivation for me to start testing early on in the app development process, instead of adding in tests much later in a bass ackwards manner.

Here’s a simple example of the output you can get from a passing Minitest:

2 + 2 === 4

Since the assertion in the math test, 2 + 2 === 4, is correct, the error message is ignored, and the string “your math is correct!” is output to Terminal.

And here’s a simple example of the output from a failing Minitest:

2 + 2 === 5

Since the assertion in the math test, 2 + 2 === 5, is not true, the test fails, and outputs the error message, “your math is wrong”, to the Terminal. The next line of code, “your math is correct!”, isn’t reached, so that string doesn’t get output to the Terminal.

More proof, indeed, that 2+2 === 4, for all you basic math haters out there.

So far I’ve just been testing “the truth” and “math” which have nothing much to do with my User model, so let’s add something a little more specific to test.

I’m borrowing the below User validation tests from this tutorial, which I’ve edited for my app’s purposes:

frank the tank’s password is dragon123, obviously

True story: creating the above tests made me realize my app was allowing users to sign up as users with empty strings as their usernames, which is not good!

I fixed that by updating my User model to include a validation for name:

validates :name,  presence: true

This all goes to show how important testing is! I hadn’t thought to test if a user could sign up for my app with an empty string for a username, but through this process of testing I found and fixed that issue.

Testing is good, all hail testing.

2. RSpec

According to Wikipedia: “RSpec is a ‘Domain Specific Language’ testing tool written in Ruby to test Ruby code. It is a behavior-driven development framework which is extensively used in the production applications.”

To get started with RSpec, add the gem to your Gemfile:

gem "rspec"

And run bundle.

Create a directory for your RSpec specifications, called ‘spec’:

mkdir spec

To get a sense of how RSpec works, I’m gonna follow this tutorial, and create a file called hello_world.spec in that spec folder. The file looks like this:

class HelloWorld
def say_hello
"Hello World!"
describe HelloWorld do
context "When testing the HelloWorld class" do
it "should say 'Hello World' when we call the say_hello method" do
hw =
message = hw.say_hello
expect(message).to eq "Hello World!"
puts "HelloWorld spec passes!"

I added in that final puts cuz I love strings, like a kitten.

i love strings like a kitten

Here’s an example of our spec passing:

And here’s an example of our spec failing:

A couple things I love about RSpec is that:

  1. It’s pretty colorful, which makes it easier to read.
  2. It tells you what it expected, and what it got, which makes it really easy to know what went wrong, and what needs to be fixed.

Now let’s do some RSpec tests that are more specific to my app.

In terms of structuring my RSpec test folders and files, I’m following this StackOverflow post, which advocates mirroring my apps file stucture. For example:


I wrote some specs for my User model, just like I tested it earlier with Minitest.

I also created a spec_helper.rb file, which looks like this:

require File.expand_path("../../config/environment", __FILE__)
require_relative '../app/models/user.rb'

And from my user_spec.rb file, my first line requires that file:

require 'spec_helper'

So I can access my User model. That way I can add more paths to models in my spec_helper, and simply require ‘spec_helper’ in each spec file.

Another cool thing about RSpec is that it’ll tell you when you’re specs suck.

For example, I wrote this spec:

it "should: have a name with length greater than zero" do
user ={name: "", password: "bobby"})
expect( be < 1
puts "username length is greater than zero"

And got the error:

not only FAILED, it is a bit confusing

That expect(0).not_to be < 1` not only FAILED, it is a bit confusing line was a great indication to me that my spec needed rewriting, since of course 0 can be expected to be less than 1, and the length of an empty string should not be expected to not be less than 1! Duh.

I rewrite that, and wrote a few more specs. My user_spec.rb file ended up looking like this:

frank the tank, hank hill, bobby

That last spec actually failed, till I updated my User model file with this:

validates :password,  presence: true

I wasn’t sure if I’d need that since User has_secure_password, but no reason not to validate password too. Yet another example of how testing improves code! Writing tests and writing code truly is a symbiotic experience, with a built in positive feedback loop.

Note those expect(user)not_to be_valid expectations are important for testing. It’s easy enough to know someone can create a user with a name and password, but testing for when someone CAN’T create a user (for example, with an empty string as the name, or a blank, white-space string as the name) is where the real value of testing comes in to play.

RSpec is awesome, all hail RSpec.

Wow, this turned out to be a long blog post. Your reward for scrolling this far is this amazing gif:


Welp, that’s it for this super basic Rails testing blog post.

Thanks for reading, literate internet readers!