// Internet Duct Tape

Getting Started with Ruby on Rails – Week 3 – Testing

Posted in Ruby on Rails, Technology by engtech on December 05, 2007

Learning Ruby

I’ve fallen for the hype and started using Ruby on Rails for building database driven web applications. You can follow along with my weekly experience discovering gotchas with Ruby on Rails.

Previously: Getting Started With Ruby on Rails – Week 2

(I swear, back to your regularly scheduled non-rails content soon enough)

Gotcha #1 – after_initialized is after_instantiated

Yes, after_initialized is called more often than just when you call Model.new. Use if new_record? inside of it.

Gotcha #2 – button_to has it’s own class

You can’t pass :class parameters to the button_to helper because it creates it’s own :class=>”button_to”. Use :id instead.

Use console

script/console will give you an interactive console for playing with objects. Use it! It makes debugging tiny little gotchas with ruby syntax you might not be familiar with so much easier. Type reload! in the console to reload your models after any changes you’ve made. Type object.methods to see a list of everything an object responds to.

You can use many familiar console navigation keys like Up, Down to move between previous commands and Ctrl-A for start of line and Ctrl-E for end of line.

The Migration Shuffle

When you’re building a new migration on your development database always do the following:

rake db:migrate
rake db:migrate VERSION={current version - 1}
rake db:migrate

It’ll let you know that you’ve made an error in your down method right away, instead of weeks later when you’re trying to rebuild the database.

Little Bobby Tables

At some point your going to write a bad migration and screw up your development database, so rebuild it.

> mysql -u root -p
drop database proj_development; drop database proj_test;
create database proj_development; create database proj_test;
> rake db:test:prepare
> rake db:migrate

bobby tables


Data Migrations

If you’re building data migrations, always uses .save! so that it will fail on a validation error and you may want to litter your migration with puts statements to jump to which object is failing validation. There’s probably a better way of doing this using fixtures, or using –trace to find which migration failed.

Or hell, don’t use a data migration for bulky legacy data.

There’s Something About Tests

I really like how simple it is to write fairly complicated tests. One thing I didn’t like was how many tests it is possible to write. The examples from Agile Web Development with Rails showed them creating a lot of tests for the validates_* helpers. Unfortunately, you don’t need to create tests that duplicate those helpers because they are bulletproof. You do however need tests to prove that you used them correctly.

Cut-and-paste errors do happen, and double checking my validations did reveal at least one case where I thought I was validating a field but I wasn’t. Not to mention that if you’re using a regular expression filter to validate the format of a field you might forget to put start and end delimiters on it. Even testing something simple like all values are in the list is useful because you might have another validation that invalidates one of the values from your list.

Ruby is Dynamic

One thing I can’t stress enough is how much you NEED unit tests. Ruby is a dynamic language, and as such there isn’t a great and easy way to find out if the code will blow up without running it. If you run it by hand you won’t find all the interesting scenarios for the simple reason that you won’t be rechecking features you implemented last week that exploded because of a change you made this morning. You need a regressable test suite.

And there’s nothing like writing a test to make you realize how much more complicated you’ve made things than they need to be.

How to Run Tests

Run an individual test

ruby test/unit/testname.rb

Run multiple tests:

rake test # run all test
rake test:unit # run unit tests

They can all be done inside of emacs by using the Tests drop down menu in rails-mode. This is the preferred method because you can click on errors and go directly to that file.

rails-mode also lets you use C-c C-c . to run the current test file. This allows you to rapidly iterate through test development.

Running Tests – Verbose Assertions

Here’s another tip that I didn’t realize at first: you can supply a message argument to your assertions that will display when it fails. This is essential if your using loops in your tests, IE: looping over an array of invalid field values, because the line number isn’t enough information to find out why the test failed.

Debugging a Test – Breakpoint

You can use the breakpoint keyword where a test is failing. This will open up a console at the breakpoint spot. Unfortunately it doesn’t work well inside of emacs because the ROutput buffer is read only (in fact, you’ll have to kill the process). So run the test from the command line when you want to play with breakpoints. I can’t seem to find a way to access the local variables in a method… so on to ruby-debug.

Debugging a Test – rdebug (or redbug according to Microsoft Word)

sudo gem install rdebug -y

in config/environments/test.rb

require 'ruby-debug'

Then use the debugger keyword instead of the breakpoint keyword where you want to stop. Don’t use it when you’re running tests from emacs because things will look weird.

Running Tests – Fixtures – Validating Fixtures

Here’s the fun bit: sometimes you break your fixtures. Not on purpose, to test bad data, but because your erb goes a little wrong, or because they’ve gotten out of date with your schema. Here’s a rake task that will let you do rake db:fixtures:validate

If you are using erb to generate your fixtures, you can also see how your fixture will roll out using:

erb test/fixtures/fixturename.yml

And while you’re at it, you probably want to validate your existing database against your models. Here’s a rake task that will let you do rake db:validate_models

Running Tests – Advanced – autotest (part of ZenTest)

There’s a plugin called autotest that will automatically run tests on any files that have changed. This is great because you can keep the console open in the background and it will immediately catch if you’ve saved a file with a typo! No need to go to the web browser, navigate to the changed page and hit refresh. In fact, using the web browser should be an afterthought… you should be able to create tests for any features.

sudo gem install ZenTest
autotest -rails

One gotcha: disable autotest if you’re manually running tests as well! You’ll end up creating duplicate records in the test database. The solution is: don’t manually run tests with rake at the same time as autotest.

Walkthrough of autotest: http://maintainable.com/articles/dry_up_testing_with_autotest

There’s a way to integrate autotest into emacs.

Running Tests – Advanced – RedGreen (for autotest)

Not the horrible Canadian TV show, but a notifier for autotest status reports.


Running Tests – Advanced – ZenTest

ZenTest is useful for parsing your rail files and creating stubs of tests.

Running Tests – Advanced – Test::Rails (part of ZenTest)

Test::Rails provides a mechanism for splitting functional tests into controller tests and view tests. This decoupled lets you check your business logic as is, and your view routing as is.

If you want to add a generator for creating view/integration/controller tests:

./script/plugin install http://topfunky.net/svn/plugins/vic_tests

Some collected thoughts about Test::Rails

Running Tests – Advanced – Rcov

Rcov is another tool that will help your testing by calculating the code coverage of your tests. This is an essential tool to find holes in your testing strategy. All the usual caveats of code coverage apply.


sudo gem install rcov
rcov test/path_to_specific_test.rb - or - ./script/plugin install http://svn.codahale.com/rails_rcov

Now you can do

rake test:units:rcov


Running Tests – Advanced – Heckle

Heckle mutates your code to see if the tests actually check anything. Unfortunately highly coupled code is heckle-proof because changing anything breaks everything else.

sudo gem install heckle

Running Tests – Measuring – Flog

Flog measures reports a score based on how complex it thinks your code is. The higher the score, the higher the chance that there is a bug hiding there.

sudo gem install flog

A Handful of Blogs About Rails Testing

These guys have written a lot (all?) of the plugins I’ve mentioned and are worth checking out if this stuff interests you:

Related Posts