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.

# Gemfile group :test do

gem 'minitest-reporters'

end

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

# test_helper.rb require '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.

# Gemfile group :test do

gem 'minitest-rails-capybara'

end

Then load it as well.

# test_helper.rb require '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.

# Gemfile group :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.

# Guardfile guard :minitest, spring: true do

…

SimpleCov

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

# Gemfile group :test do

...

gem 'simplecov', require: false

end

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

# test_helper.rb require '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.

# Guardfile guard :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.