At work, I’ve recently been downplaying the importance of Gibbon being distributed as a library, since I don’t really think it’s the code that’s important… the technique is where it’s at. As such, I’m not going to give the hack itself or its configuration any stage time in order to jump in and talk about how to use it and what its limitations are.

Monkeying Around

By and large, Gibbon’s syntax apes Cucumber’s take on Given/When/Then Templates.

There are, however, some gotcha’s and limitations and that’s what I’d like to focus on. Let’s start off with an example:

  Feature "A Tomatoist does a pomodoro" do
    Story <<-eos
    In order to perform a focused unit of work
    As a Tomatoist
    I want to start a pomodoro
    eos

    Scenario "Starting a pomodoro" do
      When "I go to the home page" do
        executes { visit '/' }

        Then "I should be sent to a new session" do
          current_url.should =~ /\/\w{3,}/
        end

        And "I should see an unstarted timer" do
          response.should have_tag('#timer .countdown_row','00:00')
        end

        And "I should see a pomdoro button" do
          response.should have_tag('input[type=submit][value=?]','Pomdoro')
        end

        When "I click the pomodoro button" do
          executes do
            @session_url = current_url
            click_button 'Pomodoro'
          end

          Then "I should be on my session's page" do
            current_url.should == @session_url
          end

          And "my timers should have been initialized" do
            response.should have_tag('#timer .countdown_row','25:00')
          end

          And "my timer history should show the current pomdoro" do
            response.should have_tag('#history ul li', /Pomodoro/, 1)
          end

          And "the pomodoro button should be highlighted" do
            response.should have_tag('form.current input[type=submit][value=?]','Pomdoro')
          end
        end
      end
    end
  end

And here’s what the output of that feature looks like using RSpec’s built in nested formatter:

A Tomatoist does a pomodoro
  In order to perform a focused unit of work
  As a Tomatoist
  I want to start a pomodoro

  Scenario: Starting a pomodoro
    When I go to the home page
      Then I should be sent to a new session
      And I should see an unstarted timer
      And I should see a pomdoro button
      When I click the pomodoro button
        Then I should be on my session's page
        And my timers should have been initialized
        And my timer history should show the current pomdoro
        And the pomodoro button should be highlighted

Flinging Poo

There are a couple of things you should note about the syntax straight off:

  1. It’s verbose.
  2. It relies heavily on nesting (sometimes in ways that feel awkward).

It’s also noteworthy that the primary means of interrogating the response is through either the have_tag matchers or using something like contain to look for text. This is not necessarily a bad thing, but it can lead quickly to close coupling unless you are constantly vigilant. I’m still mulling this aspect over, but as it stands, I haven’t thought of a better way to handle it.

Monkey wrenches

I’ve talked some to Tim Pope about Gibbon, since he’s a big fan of Cucumber driven development. His criticism, in a nutshell, is that the English text is not executable. He asserts that Cucumber keeps you honest by actually mapping the text to executable code. This is definitely valid; I frequently make the same argument about comments: “they’re lies waiting to happen”. It’s only a matter of time ‘til they become stale and the code itself is more recent. I would argue though, that Cucumber only separates you from that same fate by virtue of the author’s diligence.

Tackling the problem of example descriptions diverging from implementation from the opposite direction is Jim Weirich’s recent entry into this field, Given. Given eshew’s explanatory text altogether, preferring to let the code speak for itself. Now we’re talking! Combine that with something like Stories’ ability to convert code to plain English for output and you’d have a really nice offering. What this solution still lacks though is the facility of RSpec’s matchers, as Given is built on top of Test::Unit (as is Stories).

Monkey Gone to Heaven

For now, I’ll be sticking with Gibbon, since it provides me access to RSpec’s matchers, is crazy simple and gives me pretty much everything I require:

I’d love to hear from you in the comments about what your experience is with integration testing in general and how you’re scratching that itch these days.

Home