Archive for June, 2008

What’s up with Hoe

Wednesday, June 11th, 2008

I just don’t get it. Hoe looks like a convenience library for creating and deploying gems. But it’s not convenient at all. In fact, due to the extremely sparse documentation, it seems more difficult to use that the standard rake tasks that everybody already has installed.

Maybe I’m missing something, but having worked with Hoe on a project for the last few weeks, the most satisfying part was ripping the damn thing out of my project.

Disclaimer: I used newgem to build my project, so it could be their provided templates rather than Hoe itself that are so confounding.

Acts As State Machine

Monday, June 9th, 2008

What the heck is a state machine and why should you use one? Wikipedia say:

A finite state machine or finite state automaton or simply a state machine, is a model of behavior composed of a finite number of states, transitions between those states, and actions.

Put simply, a finite state machine (FSM) is a design pattern for handling the progression of an object through a set of arbitrary “states” and the transitions between those states. This is a really useful concept whenever you have some data that moves through a workflow. Let’s look at the example of a comment on a blog entry. The “happy path” steps are as follows:

  • A user posts the comment
  • The comment is run through an spam filter
  • The comment is approved by the moderator
  • The comment is displayed on the blog

(more…)

Unit Testing Saves the Day

Sunday, June 8th, 2008

I had been using XMLSimple to parse a bunch of XML input coming from Flex. The client discovered a sequence of events that would cause XMLSimple to stop parsing the CDATA from any XML until the server was restarted. After trying to debug what on Earth could be causing this issue and getting nowhere, I decided to just rip out XMLSimple and use the more battle hardened REXML for my parsing.

Lucky for me, I’d gone to the trouble to write good tests for these actions. It only took me a few minutes to completely change the way the handler was parsing the XML and, because I have a good test suite, I was able to confidently deploy the new version without introducing any new issues. Needless to say, the client was quite pleased. Thank you unit tests!

Testing Rake Tasks

Friday, June 6th, 2008

I recently worked on a project where I was essentially building a library of rake tasks. Obviously, I wanted to be a good citizen and unit test them. Here are a few notes on techniques I used.

You’re going to want to create a complete sample project to test against. One tricky thing about creating a library rather than an app is that you need an app to test against. It actually turns out to be really helpful because you can create exactly the application you need to test against and leave anything unrelated out. For example, if your task is going to take a bunch of code and bundle it into a gem, you’ll want to put together a very simple bit of code in the proper structure so you can test against it. Put things in your code that are easy to grep for.

You don’t always need to run your tasks for every test. For example, if you have some file or rule based tasks, use the Task#requirements array to your advantage. If something’s not working as expected, it makes sense to first make sure your rules are choosing the proper files. This goes for any set of task dependencies.

Do something about rake’s output. Rake likes to tell you all about the marvelous things it’s doing. This can make reading your test results really freaking difficult. I found a really sweet module in rake’s own test library called CaptureStdout. It provides a two methods, capture_stdout and capture_stderr. These methods accept a block and silence the output of anything executed within them.

Make yourself some convenience methods. You can execute tasks from within a rake environment using Rake::Task[:task_name].invoke. How many times do you want to type that? If your answer is anything shy of “One million please!”, you probably want to make yourself a helper for that. My recommendation is that you buddy your helper up with capture_stdout in any way you find clever.

Think about any environment conditions that may effect your code. This is especially something to consider if you’re dynamically generating tasks based on some external variable (such as RAILS_ENV). The best way I’ve found to handle this is to create separate test files for each environment that need to be tested specifically. Then, just make sure you set the property before you require your library.

Use your setup method efficiently. Make sure you clean any temporary or generated files to give the next test a clean working environment.

Think about how long tasks will take. If you’re only testing a subset of the functionality of your library, choose to test against the most specific task possible. Otherwise, you will end up waiting a long time for your full stack to run in every test.

Lastly, remember that rake, by default, will remember if a task has been run and keep it from running again in the same execution. This is great for avoiding circular dependencies in a running app, but it makes testing just that much more a pain. Allow me to offer this snippet for your enjoyment:

Rake.application.tasks.each {|t| t.instance_eval{@already_invoked = false}}