Testing is helpful for ensuring that your code runs (driver code). This is to make sure that current features work, old features still work, and future work will be easily tested. By default, every Rails application has three environments: development, test, and production.
Rails offers three kinds of testing:
- Unit tests: In the context of Rails, unit tests are meant primarily to cover the domain logic in your models, which include things like validations, calculations, search methods, and any other interesting functionality that your models implement.
- Functional tests: These provide a way to verify that the actions for a single controller are working as expected, and allow you to do things such as post data to a specific action and verify the correct response is returned
- Integration tests: Any given session with a Rails application will span across several models and controllers. Integration tests provide a way to test those kinds of interactions. Essentially, an integration test is written at the story level, allowing you to verify the correct behavior of your application for a given use case.
RSpec is testing tool for the Ruby programming language.
- Tests should be reliable
- Tests should be easy to write
- Tests should be easy to understand
Note: If you have rails 4 you can run a specific version of rails new with ruby rails new _3.2.13_ your_app
Installing rspec with rails is easy and fun! use:
- rails new your_project_name -T This will make a new application skeleton without test-unit
- cd your_project_name
- open your gemfile and add:
group :development, :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'faker'
end
- bundle install
- rails g rspec:install
please note this won't work unless you have included rake in your gemfile and then run bundle
============
So what did we just install?
- rspec-rails: includes RSpec itself in a wrapper to make it play nicely with Rails 3.
- when you generate just about anything it will also generate basic tests for whatever you generated along with it. Generate is a bad word now, but this will be nice in the future
- factory_girl_rails: replaces Rails’ default fixtures for feeding test data to the test suite with much more preferable factories.
- faker generates names, email addresses, and other placeholders for factories.
- Rspec writes human readable tests in rspec.
- This is a breakout of a typical rspec test http://imgur.com/FAK4JBK
The following code is testing the very familiar numberal to arabic in Rspec:
require_relative "numeral_calc.rb"
pairs = [
[1, "I"],
[2, "II"],
[4, "IV"],
[5, "V"],
[6, "VI"],
[7, "VII"],
[9, "IX"],
[10, "X"],
[11, "XI"],
[1982, "MCMLXXXII"]
]
describe "Numeral Function" do
pairs.each do |limit, glyph|
it "should return #{limit} for #{glyph}" do
convert_arabic(glyph).should == limit
end
end
end # Numeral Function
- the output of this in the terminal give you easy to read code explaining your failing and passing tests
- Each of these specific tests describes "Numeral function" Simlarily your tests covering lets say a user controller will be
describe "user controller" do
it "should allow a user with passing validation to be created" do
User.create(name: "passing name").should == User.find_by_name("passing name")
end
- rspec test descriptions like commit messages should be concise and descriptive to someone who doesn't know your code
Be clear about what method you are describing
BAD
describe 'the authenticate method for User' do
describe 'if the user is an admin' do
GOOD
describe '.authenticate' do
describe '#admin?' do
Use contexts
BAD
it 'has 200 status code if logged in' do
response.should respond_with 200
end
GOOD
context 'when logged in' do
it { should respond_with 200 }
end
TBC
require 'spec_helper'
describe Contact do
it "has a valid factory" do
Factory(:contact).should be_valid
end
it "is invalid without a firstname" do
Factory.build(:contact, firstname: nil).should_not be_valid
end
it "is invalid without a lastname" do
Factory.build(:contact, lastname: nil).should_not be_valid
end
it "returns a contact's full name as a string" do
Factory(:contact, firstname: "John", lastname: "Doe").name.should == "John Doe"
end
describe "filter last name by letter" do
before :each do
@smith = Factory(:contact, lastname: "Smith")
@jones = Factory(:contact, lastname: "Jones")
@johnson = Factory(:contact, lastname: "Johnson")
end
context "matching letters" do
it "returns a sorted array of results that match" do
Contact.by_letter("J").should == [@johnson, @jones]
end
end
context "non-matching letters" do
it "does not return contacts that don't start with the provided letter" do
Contact.by_letter("J").should_not include @smith
end
end
end
end
For more information, please visit: http://everydayrails.com/2012/03/19/testing-series-rspec-models-factory-girl.html