Cuke4Nuke: Cucumber for .NET Teams

Update: If you’ve just landed here, you could get the impression from this post that Cuke4Nuke doesn’t exist yet. It does. Check out this screencast showing what you can do with it as of early December 2009.

If you’ve read this blog for a while or talked with me about functional test tools, you’ve heard me talk about Cucumber. It’s my favorite ATDD tool because it’s so good at mapping stories and acceptance criteria to automated functional tests. Product Owners and BAs write acceptance criteria in natural language. Developers and testers unobtrusively automate tests for them. Anyone on the team can run the tests and see the current state of the system.

Here’s a simple example:
Feature: Google search
In order to find things on the web
As a user
I want to search for web pages containing specific text

Scenario: Load search page
When I go to the search page
Then I should be on the search page

Scenario: Search
Given I'm on the search page
When I search for "richard lawrence"
Then I should see "www.richardlawrence.info" in the results

This reads almost exactly as I teach Product Owners to specify acceptance criteria. But it’s not just text. It’s a potentially automated test.

A developer or tester can come along and automate this test like so in Ruby:
# assuming @google is an instance of a test DSL that wraps Watir, Selenium, etc.

When /^I search for "(.*)"$/ do |query|
@google.search_for query
end

Then /^I should see "(.*)" in the results$/ do |expected_text|
assert { @google.results_contain? expected_text }
end

# etc...
Each of the Given/When/Then calls is a step definition. When there’s a matching line in a Cucumber test, the step definition gets executed.

Recently, support was added for step definitions in Java via a project called Cuke4Duke:
@When("I search for "(*)"")
public void search(String query) throws Exception
{
google.searchFor(query);
}

@Then("I should see "(*)" in the results")
public void checkResults(String expectedUrl)
{
assertThat(google.containsResult(expectedUrl), is(true));
}

Now, a Java team can use Cucumber without ever writing a line of Ruby.

Unfortunately, there’s nothing like this for .NET teams. Until now (or soon, anyway)…

AA-FTT and the Birth of Cuke4Nuke

Last month, I attended the Agile Alliance Functional Test Tool conference (AA-FTT for short). AA-FTT is an open space conference. I came with one goal: to get together with other people who want Cucumber for .NET and start making it happen. I wasn’t sure anyone else would be interested, so I was thrilled with the reaction.

Photo 2 of 4 from #aaftt in Chicago at the pre-conference wor... on Twitpic

Aslak Hellesøy introduced Cucumber for those in the group who hadn’t used it and then talked through the multiple language support he’d recently added to the tool. Then, we discussed ways to build .NET support. The obvious solution was to use IronRuby and Cucumber’s language support to handle C# step definitions. Matt Wynne downloaded the latest IronRuby and installed Cucumber on it. He kicked off a simple Cucumber example, and we waited. And waited. Some two minutes later, we had results from tests that take less than two seconds to run under the standard Ruby interpreter. In a process that values frequent, fast test runs, IronRuby was a non-starter. (If you want to try Cucumber under IronRuby, here are some instructions.)

So we discussed other options and settled on using a simple wire protocol for Cucumber to communicate to .NET out-of-process, similar to Slim in FitNesse. And here’s the best part: we started building it. Matt and I paired right there to start fleshing out the wire protocol (with Cucumber tests, naturally). Later in the week at Agile 2009, Matt and Aslak paired to build the Ruby side of the wire protocol, and Matt and I tackled the first bits of the .NET side. Last week, I got the skeleton of the .NET side working and up on GitHub. You can define simple steps in C#. Cucumber can ask the .NET wire server to tell it about the steps it has and to invoke them and return the pass/fail results.

About a week ago, Aslak announced the project on the Cucumber mailing list and recruited more contributors. Declan Whelan, Scott Ford, Åsmund Eldhuset, Anders Hammervold, Chris Kooken, and Steve Eley have already stepped up with ideas and code.

Getting Involed

How can you get involved? I’m glad you asked.

  1. Join the mailing list.
  2. Fork the GitHub repository and work on one of the features in the backlog.
  3. Post a message to the mailing list to let us know what you’re working on. I’ll tag the ticket in the backlog with your GitHub username so we don’t duplicate effort. Prefix your message subject with [Cuke4Nuke].
  4. Comment on tickets in the backlog.
  5. Try using Cuke4Nuke as we develop it and give us feedback via the mailing list.
  6. Shout encouragements in the comments here and on Twitter to let us know you care, even if you can’t contribute.

Related Articles

Responses

  1. @Neil – The biggest difference is that Cuke4Nuke actually uses Cucumber as much as possible rather than reimplementing Cucumber in .NET. Quite often features are added to Cucumber that require no changes to Cuke4Nuke. Cuke4Nuke users get these features right away, while SpecFlow users have to wait until the new features are explicitly added to SpecFlow.

    Cuke4Nuke doesn’t yet have support for table diffing, so SpecFlow has an advantage there, I believe. SpecFlow also seems to have Visual Studio integration.

    Otherwise, in terms of day-to-day use, there’s probably little difference.

  2. Hello Richard,

    I have a question about using IronRuby instead of MRI Ruby. Has anyone or have you attempted to use IronRuby for the Cuke4Nuke?

    Thanks!

  3. @Michael – Not that I know of. We’ve talked about doing an in-process version of Cuke4Nuke using IronRuby the way Cuke4Duke uses JRuby, but AFAIK start up time is still an issue.

  4. @Marcel – I haven’t tried IronRuby since before it hit 1.0. I’ve heard performance is still an issue, but I haven’t confirmed. In any case, running Cucumber under IronRuby isn’t enough to write step definitions in a language other than Ruby (for example, C#). One day, we may do a version of Cuke4Nuke that uses IronRuby the way Cuke4Duke uses JRuby, but for now, I’m sticking with the current approach.

  5. Hello Richard,

    I’ve started to use SpecFlow, which, for what I’ve seen of Cuke4Nuke, it is pretty similar… or at least along the same lines.

    Right now I have an issue that has to do with the fact of how to pass state between different scenarios. When the scope of the scenario being tested is limited to the class in which you are standing, it shouldn’t be a problem… you can store the state -whatever that is- in a private member.

    But when you define your “Given” or your “Then” in a separate file in benefit of reusability, how do you manage to maintain state?

    Thanks,
    Kevin

    1. @Kevin –

      I don’t know SpecFlow well, so I can’t answer how it would behave, but I can answer your question for Cuke4Nuke, assuming they work similarly. (I notice you’ve asked the question on the SpecFlow group and received an answer, so this may be unnecesary.)

      To share state between step definitions in different classes with Cuke4Nuke, you have both classes require an instance of the same class in their constructors. Cuke4Nuke will ensure they get the same instance.

      Cucumber’s runtime model treats each scenario as independent. Cuke4Nuke does the same. So, you can’t share state between scenarios in your test code. You could preserve state in your app, but it’s a good practice to treat scenarios as independent.

  6. Thanks Richard.

    Yes… I didn’t mean to share state between different Scenarios but within the same scenario but different Steps, with the possibility that those steps are defined in different classes.

    Yes, I posted a question but none of the answers have convinced me 100%. I don’t like quite like any of the 4 options SpecFlow provides.

  7. I found SpecFlow to be extremely good and it is completely based on .NET. No Ruby or IronRuby installation required…

    Is Cuke4Nuke still active, or do you suggest to use SpecFlow, instead of Cuke4Nuke, henceforth?