Archive for August, 2006

Autotest for Rails

The zentest module for Ruby has five different pieces, but I’m specifically interested in autotest and Test::Rails. You start up autotest and it watches your files to see what changes. When a file is saved, autotest notices and kicks off unit and functional tests that were affected, so it’s speedy. It’s instant feedback!

I keep putting off trying to do test driven development (TDD) because, well, it’s not how I’ve done it before. The idea of writing tests hasn’t been my idea of a good time. However, I’m getting motivated to try it out now, partly because of autotest. Instead of writing larger chunks of code, then going back and adding tests for that section (or not adding tests) I’m going to try writing tests first.

Now that I think of it, I do spend a lot of time just waiting for a page to refresh, then it’s not quite right and I debug it, and so on. Or, I think “Oh, maybe that should be green” and I play with the styles or something, instead of keeping in flow of application development.

Some quotes about the whole test-driven development/zentest/autotest idea:

It makes it hard NOT to do test-driven development. You see the screen sitting there like a hungry fire waiting for another test. Like a fire, it also has an infinite hunger, so you will never beat it. — topfunky

Improves feedback by running tests continuously.
Continually runs tests based on files you’ve changed.
Get feedback as soon as you save. Keeps you in your editor allowing you to get stuff done faster.
Focuses on running previous failures until you’ve fixed them.
zentest page

So, I’m convinced. Well, I’m convinced to try it. Maybe it’ll just suck, but maybe I’ll bring something away from it. Let’s get down to it.

Here are some of the questions I had when getting started using autotest for Rails development:

Does it run on Windows?
Yes.
What environment does it run in? Production or test?
Test. In fact, you have to prepare the test environment (via a rake task) before you get started. See below.

I started by installing the ZenTest gem:

C:railsmyapp>gem install ZenTest
Attempting local installation of 'ZenTest'
Local gem file not found: ZenTest*.gem
Attempting remote installation of 'ZenTest'
Updating Gem source index for: http://gems.rubyforge.org
Successfully installed ZenTest-3.3.0
Installing RDoc documentation for ZenTest-3.3.0...

Note that I’m using version 3.3.0, so if you’re reading this and you’ve got a earlier or later version, read on with that understanding.

Get your test database ready with:

C:railsmyapp>rake db:test:prepare

On Windows, you need to add an environment variable HOME because autotest looks for a .autotest file there.

C:railsmyapp>set HOME=C:railsmyapp

Start up autotest.

C:railsmyapp>autotest -rails

I actually get an error when first starting up, but I think that’s because there’s not a previous test result file to compare to. So, change a file and watch autotest run the relevant test.

Started
F
Finished in 0.301 seconds.

1) Failure:
test_truth(MyControllerTest) [./test/functional/my_controller_test.rb:16]:
false is not true.

1 tests, 1 assertions, 1 failures, 0 errors 

Next:
RTFM. Seriously. It’s in the lib\ruby\gems\1.8\doc\ directory and it tells you a few things about how to change your tests to be better. Make sure you read the Test::Rails module documentation. There are at least three suggestions:

You will need to make three small changes to test/test_helper.rb to set up Test::Rails:

First, add the following to ‘test/test_helper.rb’ before you require test_help:

require 'test/rails'

Next, change the class from “Unit” to “Rails” right after you require test_help.

Your ‘test/test_helper.rb’ will end up looking like this:

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'test/rails'
require 'test_help'

class Test::Rails::TestCase
...

Finally, you need to add the extra rake tasks Test::Rails provides. Add the following line to your Rakefile after you require ‘tasks/rails’:

require 'test/rails/rake_tasks'

There’s more, but you really need to read the docs in order to find out how to use view tests and how controller tests are changed.

Now, lay out your application and write the test. Type them in. Watch them fail until you comment them out to start afresh.
Uncomment a test. Fail. Write code. Yes! Repeat.

I’m going to be most interested in seeing how writing the tests affects my application layout thinking. Will it force me to think earlier about what logic goes where? I’m not sure yet.

Snippets from the autotest documentation:

If you want Autotest to start over from the top, hit ^C once. If you want Autotest to quit, hit ^C twice.

Plugins are available by creating a .autotest file either in your project root or in your home directory. You can then write event handlers in the form of:

Autotest.add_hook hook_name { |autotest| ... }

The available hooks are: run, interrupt, quit, ran_command, red,

green, all_good, and reset.

See example_dot_autotest.rb for more details.

Other resources:

Comments (3)

Book Review: Programming Ruby

I’ve had this book on my desk for the past few months. It did a good job of explaining the basics of Ruby, as well as being a quick reference when I can’t remember the difference between Array.collect{} and Array.map{}.

I picked this up at the same time as the first edition of Agile Web Development with Ruby on Rails and I’m glad I learned more about Ruby before getting into Rails.

Comments

Access vs SQL Server: Updating SSN fields

I had some Social Security numbers that I needed to format. The correct format was xxx-xx-xxxx, with dashes. However, some of the values didn’t have dashes. So, I wrote this query to do the update in Access:

UPDATE BasePat
SET BasePat.SSN = Left([SSN],3) & "-" & Mid([SSN],4,2) & "-" & Right([SSN],4)
WHERE (((InStr([SSN],"-"))=0) AND (Len([SSN]))=9));

Well, then I wanted to update the query to run on SQL Server, so I had convert some functions and change how the strings were handled. This is the result:

UPDATE BasePat
SET BasePat.SSN = LEFT([SSN],3) + '-' + SUBSTRING([SSN],4,2) + '-' + RIGHT([SSN],4)
WHERE (((CHARINDEX('-',[SSN]))=0) AND ((LEN([SSN]))=9));

I had to use SUBSTRING() instead of Mid(), CHARINDEX() instead of InStr() with the parameter order switched, and change the text handling to use + instead of & and single instead of double quotes.

If you have to do a lot of this, I found this reference to be very helpful: Differences between MS Access and SQL Server at aspfaq.com

Comments