Testing Ruby: Some Time Later…

In an earlier post, I wrote about how I am trying to upgrade a long-neglected project and have been finding it difficult because I didn’t have adequate test coverage. Since then, I’ve gotten a chance to get some more experience with the tools I mentioned, so I thought I’d post an update here.

At first I was concerned that the tools that I was planning to use were young and changing quickly and I was also concerned that there seemed to be a lot of them. The latter concern hasn’t been too much trouble, although the former is a factor. Since that post all of the tools involved have revved, sometimes breaking compatibility with another. Issues haven’t lasted long, and it was always possible to wait to upgrade until the rest of the ecosystem caught up.

I haven’t done too much with Rspec specs yet, as I’ve been trying to cover my app’s behavior at a higher level with Cucumber and Webrat. Specifying the behavior of the app at a user level has been valuable in helping me update the application to the latest stable version of Rails (now 2.3.5) while still being reasonably certain that I haven’t done anything to screw up my app’s users.

I hadn’t deployed this app to production in many months, and I’ve since been using Git and GitHub as version control for the project, having converted my SVN repo to Git awhile back. That, along with Capistrano having evolved some, necessitated a revisiting of my deployment recipe. This was pretty straightforward, and I really like the simplicity Capistrano brings to deployment.

So, with a new recipe and an updated app with some tests and a new Rails version, I pushed the button…and it worked! Feels good to get that old project on the way to health, and this was a big first step to that.

It wasn’t without issue, though. The main page has a listing of how many comments a given posting has, and when someone comments on a post it gets incremented via the counter_cache mechanism Rails provides. For some reason this count is now being incremented twice for each new comment, and it only happens in production. Luckily, this isn’t exactly a big problem, so I’ve filed it as minor in my bug queue after doing an initial investigation that didn’t turn up an easy fix.

Back to the testing, I was already somewhat overwhelmed by the number of frameworks involved in BDD, and it turns out I needed some other tools too. I’d previously used fixtures for test data and was well aware of the pain they caused as the number of tests grew. So I looked into using a factory for test data, finding factory_girl and machinist. I’d found factorygirl first and started using it before coming across machinist. I like machinist’s API better, but since I’ve already gotten over the (admittedly not too steep) learning curve for factorygirl, I decided to stay with what I’ve got.

Machinist’s examples used Faker for providing test data in factory-created objects (which I briefly posted about previously), and it’s been a nice addition to the toolbox. I use it in conjunction with factory_girl, and have been pleased with how transparent but still readable things are with this method.

I’ve also stuck with RubyMine, which is now at 2.0.1RC and is pretty good. Coming from IDEA, whose inline error detection is bulletproof, it’s a bit of a shock how often it can’t figure out where a method has been defined (if at all). There is a lot of magic that Rails brings to the party, particularly in ActiveRecord objects, so I guess that it shouldn’t be that much of a surprise when it can’t figure it out. RubyMine’s built-in Cucumber scenario runner is handy for what I’ve been doing. Its Git integration is nowhere near as good as its SVN one though, and I do most interaction with Git on the command line still. I like RubyMine quite a lot and plan to stick with it. I hope it continues to evolve and improve.

Overall, it’s been quite a lot to learn, but it’s felt good to do it. Now, I need to get more coverage of the critical user scenarios in Cucumber so I can get into some of the really crufty code and replace it with new idioms that have evolved since the code was originally written. I’m particularly looking forward to pulling out a lot of the database conditions into named scopes and replacing some of the hacks I’ve got with Rails observers and other hooks. I’m sure that lower level of code change will prompt me to get to specifying behavior in Rspec, too.