Or little computing tricks and hacks
Testing with RSpec in Rails, Part 1, Introduction
January 22, 2015Posted by on
Testing in Rails is both hard and easy. Hard because it takes as much time as coding does, but easy because there are many tools that make the most complicated things straightforward. There are so many tools though, that sometimes it is hard to choose. Neat paradox.
When setting up testing for my app, I did not find in one place a comprehensive explanation of the Rails testing process as a whole. This is an attempt to fix the situation.
The issue is more what and when to test. Michael Hartl has an introduction to testing in his Ruby on Rails tutorial, which describes why testing and the kinds of tests he is likely to do. In summary,
- first test the controllers and the models, in other words
- second test the functionality across models, views and controllers, the
- and third, the views, but if they are likely to change, they can be skipped.
He also mentions the importance of writing
regression tests on bugs found and having tests in place before any refactoring.
RSpec testing infrastructure
When a new Rails project is created with default settings, a
test directory is created, coupled to work with
minitest. From the word GO, I started using
RSpec (http://rspec.info/, since I used the Ruby on Rails tutorial mentioned above which used
RSpec as testing framework. I believed it has changed since.
I did not want that default directory, as I wanted the RSpec set up.
By issuing the command
rails g controller StaticPages about --no-test-framework
the test files related to the
StaticPages controller will not be created. To create the right files, RSpec must be installed. That is done by including its gem in the Gemfile.
RSpec takes advantage of a series of helpers to run tests automatically. The gems are specified following:
group :development, :test do gem 'rspec-rails' gem 'factory_girl_rails' end group :test do gem 'selenium-webdriver', '2.35.1' gem 'faker' gem 'capybara', '>= 2.2.0' gem 'guard-rspec' gem 'launchy' end
and then run bundle.
In my opinion, the most interesting about Rails testing, is the interaction with databases and
RSpec plus helpers makes this easy.
By default, every Rails application has three environments: development, test, and production. The database for each one of them is configured in
That fact is simply brilliant, as the development database is NOT the same as the test database. One can create automatically hundreds of records to test for specific features in isolation.
To run any testing, the databases need to be created, so run
which will create the databases which do not exist and inform you of the ones already created. The information on the databases description is taken from the file
config/database.yml, which should include the information about test, development and production databases. Make sure that the three are name differently!
rails generate rspec:install
which generates the following configuration files:
.rspec spec/spec_helper.rb spec/rails_helper.rb
All tests and helpers will reside in the
spec directory. This is directory where
RSpec searches for the tests to run.
NOTE: After making changes to any of the models in development, you have to migrate the changes to the test database as well by running
rake db:migrate RAILS_ENV=test
With this, the testing infrastructure is set up.
RSpec uses mainly the words “describe” and “it” so we can express concepts like a conversation:
“Describe an order.”
“It sums the prices of its line items.”
describe method creates an
ExampleGroup. Within the block passed to
describe you can declare examples using the
it method. Under the hood, an example group is a class in which the block passed to
describe is evaluated.
The broad syntax of the test is as follows:
describe Object do it "Descriptive message of the test" do code with expectations end end
Each “it” line only expects one example. Best practice is to test one thing at a time to make it simple to find errors. Although the descriptive message is technically optional, omitting defeat the purpose of individual testing. Previous
RSpec examples had the “should” beginning the message, however that just clutters the output. A direct verb suffices.
Now to writing the tests. But where to start? With how to run a test.
To run a test, use the command
from the root directory of the app. If used alone, it will run all the tests found in the
spec directory. You can also specify a directory or a filename including its path with respect to root. RSpec will run all tests found in that directory in the first case, or just the file specified in the second.
The testing framework automatically creates directories to sort out the tests. My
spec directory looks like this:
controllers/ factories/ models/ requests/ support/ helpers/ rails_helper.rb spec_helper.rb views/
Next is what to test: unit testing, integrations testing, views, regression testing.
Unit testing: Models
Models are the building blocks of the application. They are also easier to test since their behaviour should be well defined in any application. I considered them to be first priority to test.
The blog Everyday Rails considers the following to be essential model tests:
factoryshould generate a valid object
- data validation
- class and instance method
Full text deployed in a post called Testing with RSpec in Rails, Part 2, Models.
Unit testing: Controllers
Post in development.
Post in conception.
This should test the functionality across models, views and controllers.
Will I create a post?
Code in the views tend to change often, so there are different schools of thought on whether to test or not.
Automatic test runs with Guard
Guard runs the test suite upon the detection of a modification of file in the spec directory or as specified in the
Guardfile. It also sets the testing environment just once, speeding up the running of subsequent tests. To set up (gem already included in the Gemfile) run:
bundle exec guard init
which creates the
Guardfile describing how and when Guard is to run. In his tutorial, Guard: Michael Hartl’s Rails tutorial, he explains the set up in more detail, although using
minitest instead of
To start guard just type in a terminal
It will create a shell and
guard will start listening to any changes in the spec directory or any other file specified in the
Guarfile created in the set up is a very good starting point.
Type enter in the shell to run all the tests in the spec directory.
Ctl-D to exit.
Guard needs expansion.)