I’ve recently been looking a bit deeper into Test Driven development (TDD). You know, where you write a unit test first, and then write the code to fix it. I’ve been really impressed with how clean the code is that I’ve written this way, particularly in terms of its simplicity and low coupling. That got me looking for a testing framework for a Rails website I’m working on, and there I came across Cucumber. Cucumber is a Behaviour Driven Development ( BDD ) testing tool.

One of the principles of BDD is “Business and Technology should refer to the same system in the same way”, which to my limited interpretation means that business analysts should be able to read test cases.

What is really cool about cucumber is that it allows you to specify scenarios in English (or French, Sotho, etc).

Consider this example:Scenario: Admin users should be able to edit all profilesGiven a website user Admin who is an administratorAnd a website user Joe who is a userWhen a user logs in as AdminAnd navigates to the User Profile pageThen the page should allow editing of Joe’s profileAnd the page should allow editing of Admin’s profile

Scenario: Normal users should only be able to edit their own profilesGiven a website user Admin who is an administratorAnd a website user Joe who is a userWhen a user logs in as JoeAnd navigates to the User Profile pageThen the page should allow editing of Joe’s profileAnd the page should not allow editing of Admin’s profile

Pretty simple right? You can read it and know exactly what the system should do under a given scenario. There’s nothing technical there at all. In fact, the only required syntax for Cucumber are the bits in green, which must start each line. You must have a Scenario, Given, When, Then. You can have as many And’s as you need under each section to specify additional Given’s/When’s/Then’s. This structure also forces a very clear, and definite way of thinking about a problem onto you â€“ if you can’t specify it in this format (Given, When, Then) then you can’t test it (with Cucumber ;)!

Obviously there’s a chunk of work that needs to happen behind the scenes to make these scenarios run â€“ we’ll get to that later. What’s got me excited is that this seems a very approachable â€˜language’ for non-technical people to read (or in my more optimistic phases, even write) and understand.

Imagine a project where the business analysts write scenarios like these, and have a dashboard of what scenarios are working, and which not. And developers spend their time making these tests pass, safe in the knowledge that once all the scenarios pass, their work complies with the spec, and is working! Of course that’s Utopia, but Cucumber is a step in that direction. Even if it only goes as far as allowing business analysts to read what has actually been tested and translated into functionality from scenarios which are written by developers, I think it would still add a lot of value to the communication chasm we so often find between the people who define what they want, and the people who’s job’s it is to try deliver it to them.

Now Cucumber comes from the Ruby on Rails world, and there are some great plugins for it to simulate browsers, and do real integration level testing. There’s also a plugin that allows you to run it (via JRuby) in the JVM, and test Java code using Cuke4Duke, and you can do web integration testing using WebDriver/Selenium. I can’t claim to be an expert on any of this stack (or even Cucumber yet for that matter), but here’s an description of how to set up the classic calculator example to whet your appetite.

Install Maven

I have hangups against Maven from previous projects, but lets not get into that. You can also use Ant and Ivy, but the Maven way is much easier to explain.

Download Maven (Version 3.0.2 worked fine for me) and extract it somewhere.
Add the bin folder to your path
If you’re behind a proxy, set your ~/.m2/settings.xml as described here

This is a minimal configuration for maven using Cucumber for intetgration tests. All you need to do is change the project group (groupId), identifier (artifactId) and name (name). Also check the section on proxy setup â€“ Its enabled by default because I need it.

Create a features folder under your project root. This is where we’ll add features shortly.
From the project root folder (where the pom.xml is), run the following command:mvn -Dcucumber.installGems=true integration-test

This will download the maven plugins required to run the project, Cuke4Duke so we can write some features, JRuby to run Cucumber, and Cucumber and its dependencies. Depending on your connection speed and whether you’ve run Maven before, this could take a while.
You should see something like:

Adding Features

Create a features/calculator.feature containing the following:Feature: Simple Calculator exampleAs a big number cruncher userI want to be able to perform arithmeticSo that I can make lots of money

Scenario: Add 0
Given a calculator
When I add 1 and 0
Then the result should be 1

Now lets try testing our feature:mvn integration-test
You should see something like:

123456789101112131415161718192021222324252627282930313233

[INFO] -- cuke4duke-maven-plugin:0.4.3:cucumber (run-features) @ cuke4duke-java-example --[INFO] Feature: Simple Calculator example[INFO] As a big number cruncher user[INFO] I want to be able to perform arithmetic[INFO] So that I can make lots of money[INFO] [INFO] Scenario: Add 0 # features/calculator.feature:6[INFO] Given a calculator # features/calculator.feature:7[INFO] When I add 1 and 0 # features/calculator.feature:8[INFO] Then the result should be 1 # features/calculator.feature:9[INFO] [INFO] 1 scenario (1 undefined)[INFO] 3 steps (3 undefined)[INFO] 0m0.024s[INFO] [INFO] You can implement step definitions for undefined steps with these snippets:[INFO] [INFO] Given /^a calculator$/ do[INFO] pending # express the regexp above with the code you wish you had[INFO] end[INFO] [INFO] When /^I add (\d+) and (\d+)$/ do |arg1, arg2|[INFO] pending # express the regexp above with the code you wish you had[INFO] end[INFO] [INFO] Then /^the result should be (\d+)$/ do |arg1|[INFO] pending # express the regexp above with the code you wish you had[INFO] end[INFO] [INFO] If you want snippets in a different programming language, just make sure a file[INFO] with the appropriate file extension exists where cucumber looks for step definitions.[INFO] [INFO] ---------------------------------------------------------------------

[INFO] BUILDSUCCESS
[INFO]

What that’s saying is that you have 1 scenario that cannot be completed because it contains undefined steps, and that there are 3 undefined steps.
It then gives you some examples on how to create the necessary step definitions. Unfortunately they are in Ruby, but as soon as we have the first java example, you’ll see that the suggested solutions are converted to Java.

[INFO] -- cuke4duke-maven-plugin:0.4.3:cucumber (run-features) @ cuke4duke-java-example --[INFO] Feature: Simple Calculator example[INFO] As a big number cruncher user[INFO] I want to be able to perform arithmatic[INFO] So that I can make lots of money[INFO] [INFO] Scenario: Add 0 # features/calculator.feature:6[INFO] Given a calculator # CalculatorSteps.setUpCalculator()[INFO] TODO (Cucumber::Pending)[INFO] features/calculator.feature:7:in `Given a calculator'[INFO] When I add 1 and 0 # features/calculator.feature:8[INFO] Then the result should be 1 # features/calculator.feature:9[INFO] [INFO] 1 scenario (1 pending)[INFO] 3 steps (2 undefined, 1 pending)[INFO] 0m0.070s[INFO] [INFO] You can implement step definitions for undefined steps with these snippets:[INFO] [INFO] @When("^I add 1 and 0$")[INFO] @Pending[INFO] public void iAdd1And0() {[INFO] }[INFO] [INFO] @Then("^the result should be 1$")[INFO] @Pending[INFO] public void theResultShouldBe1() {[INFO] }[INFO] [INFO] ---------------------------------------------------------------------

[INFO] BUILDSUCCESS
[INFO]

You’ll see we now have 1 pending step i.e. there’s only a stub for the step for now. The @Pending annotation allows you to work on translating the steps into method calls first, and then worry about their implementation later (without forgetting to do them) Also, the examples are now Java because Cuke4Duke has figured out what language we’re using.
Define the rest of the steps:

I’m sure some of you are screaming about all these hard-coded values, and wondering what’s the point of defining everything twice, once in the feature, and again in the step class. Hang in there, we’ll tidy it up in a minute.
Now lets add another scenario to our calculator.feature:

Scenario: Add 1
Given a calculator
When I add 1 and 1
Then the result should be 2

Running the tests tells us we need to add new steps. Instead of hard coding each scenario, lets DRY, and use RegEx to group out the variables on our existing step methods:
Change the RegEx to something like:

12

@When("^I add (\\d*) and (\\d*)$")@Then("^the result should be (\\d*)$")

Run your tests again
I got:

123456

[INFO] Scenario: Add 0 # features/calculator.feature:6[INFO] Given a calculator # CalculatorSteps.setUpCalculator()[INFO] When I add 1 and 0 # CalculatorSteps.addTwoNumbers()[INFO] java.lang.ArrayIndexOutOfBoundsException: 0 (NativeException)[INFO] features/calculator.feature:8:in `When I add 1 and 0'[INFO] Then the result should be 1 # CalculatorSteps.theResultShouldBe()

This error message is a bit cryptic, and it confused me for a while until I remembered that the RegEx groups are converted into method arguments, so we need change our methods as follows:

Cuke4Duke does automatic conversions from String to your argument type.
Run the tests again, and you should see that you’ve now defined a testing language where the business analysts can add scenarios to their hearts content. Until something breaks, or the BA’s need more syntax, the developer’s job is done!

That concludes our trivial introduction to Cucumber for Java. I hope that it’s shown just how expressive tests can (and should be). I also hope that next time you have develop something, you’ll have a go at expressing it as set of a Given/When/Then’s – even if you never actually write it down, let alone run it – just to see how it affects your thinking.

A while back I read a book by Tim Ferris called “The 24 Hour Work Week”. One of the major things he recommended was using online, cheap, international resources to do your work for you.

I’ve finally taken the plunge, and recruited some graphic designers – they designed the logo, and website you see here. And all of this done through an incredible website called eLance (as in free-lance). I’ll tell you more about my experience with this site, and working with international (read Pakistani in this case) teams shortly