What?
Behavior driven coding for Ruby, and especially, Ruby on Rails.
This is a summary and run-through of the excellent RailsEnvy Love Tests presentation.
Why?
- Tests increase your confidence, and let you sleep at night.
- Writing tests before writing you code makes you write better code.
- Writing the tests and specifications first, you will know when you're done - all the tests pass!
- Tests make for excellent documentation, in the sense that Examples are more powerful than Descriptions
Also - it's fun! Do it
Red -> Green -> Refactor style with
RSpec and
Auto testing Zen.
How?Let's consider the example of a user who has forgotten her email.
Writing good
behavior specifications is like telling a short story - a good story defines your app behavior:
A user who has forgotten a password
- Should be able to enter and submit their email address
- Should be sent an email if their email address is valid
- Should be shown a notice if the email address is invalid
- Should be redirected to the login screen if their email is valid
- Should be shown an error message if the email address is not in the system, and be shown the form again.
We use RSpec to turn our story into action.
Install RSpecWithout rails (just the gem)
gem install rspec
For rails, with its beautiful helpers
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails
./script/generate rspec
To run your tests, you just do
rake rspec
OR you turn testing into an automated game. ZenTest will run tests *every time your files change* and pop up notifications for passes/fails using Growl/Snarl.
gem install ZenTest redgreen
autotest
Coding the behaviorNow actually write the RSpec code - or just flow by turning your English into RSpec with the awesome textmate
YAML to RSpec plugin.
Direction for easy install.
On to the testing. It is important to keep the component we're testing separated from the rest of the system. E.g. if we want to test the controller of a user retrieving a lost password, we don't want it to be dependent on the Model part working correctly at test times.
Enter the stage: Stubs and Mocks.
You use these to manage "canned" answers. E.g. if you want to test for a user with the name Greg who is in the system and entered his email correctly, you do
@user = mock_model(User).stub!(:first_name).returns("Greg")
@user = mock_model(User, :first_name => "Greg")
User.stub!(:find_by_email).returns(@user)
What to test?
Every line of code you write. Seriously. In Rails you write so little code that this should be possible. However, make sure that you don't slip into testing Rails - it is already rather well tested!
ExamplesValidation
validates_presence_of :first_name
@user.should_have_at_least(1).errors_on(:first_name)
Object relation mapping
has_many :user_roles
@user.user_roles.create(:role => "Admin")
@user.user_roles.count.should == 1
UI Redirection
redirect_to :action => 'index'
response.should redirect_to(:action => "index")
Do it
Read the RSpec website - it reads like a good book
Come up with and start a New project
Keep 100% Test coverage, or at least attempt it!
Feel good about yourself
Make sure tests pass