So I was recently asked about how I test. I realized that I have a very nice setup (for me anyway) and I though I would share a bit of it with you. It keeps my testing fast and flowing. Testing can some times be such a chore, and these configurations and steps help to reduce that feeling.

Note: I have a gem

I do use a gem that configures 99% of this for me. It’s internal to my business. It has a lot of things people always look for and a few modifications that are specific to my business. For example these testing configs, and the code that auto enters tickets into my tracker when an exception is thrown. So if you see any missing parts it’s probably in that gem.

Second Note: I am not going to teach testing

That’s outside the scope of this document. If you don’t know how to write tests then this article is not for you. I would like to remind all developers out there not to go crazy with the testing. Keep it small, simple, and atomic.

The Gems

group :development, :test do
    gem 'sqlite3', :require => 'sqlite3'
    gem 'autotest-growl'
    gem 'autotest'
    gem 'autotest-standalone', :require => 'autotest'
    gem 'autotest-rails-pure'
    gem 'ansi'
    gem 'autotest-fsevent'
    gem 'fabrication'
    gem 'rspec-rails'
    gem 'spork-rails'
    gem "shoulda-matchers"
end
gem 'simplecov', :require => false, :group => :test

First, yes I load testing stuff in development. It helps track down problems with the testing framework. You may want to change that. It’s a taste thing. sqlite3 is chosen over mysql or others because it helps promote a database agnostic design. Spork makes things faster but has some gotchas, and yes I use RSPEC.

The .rspec file

--colour --drb -f h -o coverage/docs.html -f p -t ~slow

Colour is british, just pretend it says color. –drb tells rspec to use spork. -f h tells it to use HTML -o coverage/docs.html is output the HTML to a file. -f p tells it to use the default dots output.

I output to HTML so that I can look at the results in a browser, and then use the default to help autotest (and the command line) get back reasonable STDOUT for parsing.

I also tag slow tests and don’t run them after they pass once. This means tests need to be manually run every once-in-a-while, but thats far better then running 30 60 second tests every time you save a file. Normally these are API consumption tests, and end up getting mocked or stubbed in other tests.

Autotest

I like it better the guard, so thats what I use. Guard should work here as well. Here is the ~/.autotest file:

require 'autotest/growl'
require 'autotest/fsevent'
require 'ansi'

Autotest.add_hook :red do |at|
    system("afplay ~/.bin/red.mp3")
end

Autotest.add_hook :green do |at|
    system("afplay ~/.bin/green.mp3")
end

Growl does what you think. Makes it grow test status, much better then staring at terminal. Fsevent helps autotest hook in for “file changed” events, instead of polling, it’s much faster. The hooks play sounds that help me notice failures in another way.

Apache Config

I always test using apache and passenger. Too many times in the past I have been bitten by issues that are highlighted with passenger that mongrel, webrick, etc. just ignore. This means that my dev setup is closer to production.

<VirtualHost *>
    ServerName  test-project.coteyr.net
    DocumentRoot /Users/coteyr/Projects/test-project/public/
    <Directory /Users/coteyr/Projects/test-project/public/ >
        AllowOverride All
        Allow from all
        Options -MultiViews
    </Directory>
    Alias /coverage /Users/coteyr/Projects/test-project/coverage
    <Directory /Users/coteyr/Projects/test-project/coverage >
        AllowOverride All
        Allow from all
    </Directory>
</VirtualHost>

The important part there is the alias to something outside the public directory.

The Test Helper

I am not going to post the entire file. It’s too big, but the important part is:

Spork.prefork do
    unless ENV['DRB']
        require 'simplecov'
        SimpleCov.start 'rails' do
            add_filter "/specs"
        end
    end

########More stuff Here 
Spork.each_run do
    # This code will be run each time you run your specs.
    if ENV['DRB']
        require 'simplecov'
        SimpleCov.start 'rails' do
            add_filter "/specs/"
        end
    end
end

All together now

Here is a screen shot of a project in the very early stages.

A project in the very early stages of testing.
A project in the very early stages of testing.

Ok, so like most developers, I do the standard write a failing test, fix code, test passes cycle. The only difference is that I don’t look at the terminal. It’s there in the background running. So in Terminal:

spork &
autotest

Then in a browser (I use chrome for developing). Go to:

  • http://test-project.coteyr.net/
  • http://test-project.coteyr.net/coverage/index.html
  • http://test-project.coteyr.net/coverage/docs.html

This allows you to watch the browser for pass/fail and use it to make sure the site “looks” right. Having the coverage report open also gives you a quick glance at if your cheating without noticing. Growl (and the sounds) tells you the status of the test run, and the browser will tell you the details of the error in a nice pretty highlighted way.

I should also mention that I use LiveReload to auto refresh pages as they get updated by me or by autotest/rspec.

Gotchas

I only run into 3 gotchas. First, spork is a bit different then running rake from the command line. Most notably it doesn’t reload the entire environment every single run. This means that if you add gems or do other things where you would normally restart the web server, you also have to restart spork.

Second, your not running rake and autotest doesn’t auto migrate the database. So if you make database level changes you need to run rake once. I don’t feel that this is a bad thing because it backs up any issues that you may have missed because your running spork (like removing a gem).

Last, autotest with fsevent can only register files that exist. So if you add a file (like model or request test) autotest won’t know about it. Switching to the autotest terminal and pressing ctrl+c (there by running the entire test suite) fixes the issue.

Coteyr.net Programming LLC. is about one thing. Getting your project done the way you like it. Using Agile development and management techniques, we are able to get even the most complex projects done in a short time frame and on a modest budget.

Feel free to contact me via any of the methods below. My normal hours are 10am to 10pm Eastern Standard Time. In case of emergency I am available 24/7.

Email: coteyr@coteyr.net
Phone: (813) 421-4338
GTalk: coteyr@coteyr.net
Skype: coteyr
Guru: Profile