How I test Rails apps with Minitest, Capybara, and Guard

Heidar
Heidar
Jan 11, 2016 · 4 min read

Update: I’ve moved my blog to Hashnode. You can visit it here.

I recently made the switch from RSpec to Minitest. I like small, simple tools which I can have a complete understanding of easily. I’d rather read code than a DSL; I don’t require having my tests read like English. So Minitest is perfect for me.

Making Minitest output nicer

One thing I miss from RSpec is the nice output. There’s a gem that replaces the Minitest default output with something a bit more readable: minitest-reporters.

# Gemfilegroup :test do
gem 'minitest-reporters'
end

To make it work, just add two lines to test_helper.rb

# test_helper.rbrequire 'minitest/reporters'
Minitest::Reporters.use!

There’s a few different outputs to choose from but I like the default one personally.

Capybara

Minitest is the default in Rails now, so no additional setup is required. However, when it comes to integration tests I can’t live without Capybara. It’s easy to add Capybara to the default Rails test stack using the minitest-rails-capybara gem.

# Gemfilegroup :test do
gem 'minitest-rails-capybara'
end

Then load it as well.

# test_helper.rbrequire 'minitest/rails/capybara'

That’s all, then just write your integration tests in classes that inherit from Capybara::Rails::TestCase. I always use the default driver and only change it for specific tests which need to run JavaScript.

Fixtures

In the past I used FactoryGirl and while it’s a great tool I use fixtures now. I don’t like adding gems to my projects unless I feel like I really need to. It makes updating harder and it’s just one more thing that can break. I can’t seem to find a reason to use FactoryGirl over fixtures. FactoryGirl syntax has also changed in the past, making it annoying to update, especially on big projects.

Here’s an example subset of a fixture from a project I’m working on right now.

# articles.yml
programming:
title: Hello World
body: This article is about programming.
author: john
press:
title: The Free Press
body: This article is about journalism and press.
author: bill
# authors.yml
john:
name: John
publication: Programming
bill:
name: Bill
publication: Technology

Just a simple YAML files with data. Note the relationship between articles and authors. Referencing fixtures in tests is also simple:

articles :programming

If you want the functionality of FactoryGirl’s build method, then remember that ActiveRecord models are factories when you consider the class methods new and create.

article = Article.new(title: 'New Article', body: 'some text', author: authors(:bill))

Or perhaps you only care about the title, so use an existing fixture and update the title.

article = articles :programming
article.attributes = { title: 'New Article' }

Fixtures are also faster than factories. But regardless of which one you prefer, they can both become a mess when your codebase grows so keep them organized.

Guard

I practice TDD like many others in the Ruby community. I use Guard to automatically run my tests on file changes, it saves a lot of time. I work with a split screen, one side code, the other side test output. I use guard-minitest to make Guard work with Minitest.

# Gemfilegroup :development do
gem 'guard'
gem 'guard-minitest'
end

To generate a Guardfile just run:

bundle exec guard init minitest

The only thing I needed to change was to comment out the code in the Guardfile for the version of Rails I was using. Then just run guard. For my setup I made use of spring to make things a bit snappier.

# Guardfileguard :minitest, spring: true do

SimpleCov

It’s nice to have SimpleCov to see test code coverage. Add it to the test group:

# Gemfilegroup :test do
...
gem 'simplecov', require: false
end

Then at the very top (very important) of test_helper.rb add:

# test_helper.rbrequire 'simplecov'
SimpleCov.start 'rails' unless ENV['NO_COVERAGE']

Now it will write test coverage reports whenever tests are run. You probably want to add coverage to .gitignore.

Note the condition on the second line, that’s there to prevent test runs from Guard from writing coverage reports as they would be inaccurate. Finally, set that environment variable in the Guardfile.

# Guardfileguard :minitest, spring: true, env: { 'NO_COVERAGE' => 'true' } do
...

Now coverage reports will only be written when you run your test suite with Rake.

What I test

When I test my Rails apps I never bother with controller and view tests anymore unless there’s a specific reason to do so. I’ve never felt they add any value and just make changes harder. Good integration tests and small, standardized controllers remove much of the need for controller tests.

ls -F test
fixtures/ helpers/ integration/ mailers/ models/ test_helper.rb

That’s everything in my test folder.

Summary

This is how I currently test Rails apps. I’m not saying it’s the best way or anything and a lot of it is down to personal taste. But I like this approach since it’s composed of a few simple tools, some of which happen to ship with Ruby/Rails and the few things I add provide a lot of value.

I’d love to hear how you test your apps, I’m sure there are things I could do better.


Feel free to connect with me on Twitter or visit my website for more information about me.

Heidar

Written by

Heidar

I write software and make stuff.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade