BDD in .NET with Cucumber, Cuke4Nuke and TeamCity

At the Oresund Developer conference in Sweden about two months ago, Aslak Hellesoy talked about recent changes to his Cucumber Behaviour-Driven Development tool, aimed at providing better support for platforms other than Ruby. Instead of using the tool through slow Ruby ports, .NET and Java developers got a chance to benefit from much quicker native integrations using a new wire protocol that allows Cucumber to talk to external systems. Richard Lawrence and Matt Wynne were very kind to work on a native .NET integration for Cucumber, called Cuke4Nuke, which recently got up to speed with Cucumber Ruby features. In this article, I’ll show you how to set up and use Cuke4Nuke to use Cucumber for .NET BDD development.

Basic Software

  • If you don’t already have Ruby installed, install it using the new one-click Ruby Installer. You don’t have to know Ruby to write Cuke4Nuke tests, but you still need it to run Cucumber. Install the Ruby development kit as well. Alternatively use the old 1.86 installer which comes with the development kit.
  • Add GemCutter.org to the list of Ruby Gem sources. Execute the following command from the command line:
    gem sources -a http://gemcutter.org/
  • Install the Cuke4Nuke gem. Execute the following command from the command line:
    gem install cuke4nuke
  • Install the Win32Console gem to get colour reports in the windows console window:
    gem install win32console

    You might also need WAC to work around console colour problems so download that Exe and put it somewhere on the disk.

  • If you don’t already have NUnit, grab the latest version from NUnit.org. We’ll need this later as Cuke4Nuke uses NUnit assertions.

To verify that the system is set up, execute Cuke4Nuke from the command line. You should see a help screen with Cuke4Nuke options. If you see an error that the command Cuke4Nuke isn’t found, check if there is a Cuke4Nuke.bat executable in your Ruby bin folder (C:\Ruby\bin if you accepted the default installation options for Ruby), whether that folder is on your executable path and whether Cuke4Nuke gem exists in the gems folder (C:\Ruby\lib\ruby\gems\1.8\gems\cuke4nuke-0.3.0 on my system).

Project setup

Create a normal C# class library project and add a Features folder to it. This is where your Cucumber scenarios will go. Add a step_definitions subfolder to that and create a file called cucumber.wire, with the following content:

host: localhost
port: 3901


This tells Cucumber to connect to an external system on port 3901, the default port for Cuke4Nuke. Now let’s add a test scenario to make sure that everything is working correctly. Create a file called basic.feature in the Features folder, with the following content:

Feature: Hello World
	In order to ensure that my installation works
	As a Developer
	I want to run a quick Cuke4Nuke test
	
	Scenario: Hello World
		Given The Action is Hello
		When The Subject is World
		Then The Greeting is Hello, World.


At this point, your project structure should look as on the picture below:


Now let’s run Cuke4Nuke for the first time. Build the project, open the console, go to your project folder and run the following command:

Cuke4Nuke bin\debug\Cuke4NukeExample.dll -q

(replace the DLL path with your project output DLL). You should see the Cucumber output telling you that there is one scenario with three steps, all of which are undefined. If you do not see the colours, add the -c flag and pipe the output to WAC.exe, making the command similar to the following:

Cuke4Nuke bin\debug\Cuke4NukeExample.dll -q -c | d:\apps\wag.exe


In any case, the command result should be similar to one on the picture below:

Now let’s add the step definitions that help Cucumber talk to our project code. Create a C# class file (say Steps.cs) and paste the following code:

using System;
using System.Text;
using Cuke4Nuke.Framework;
using NUnit.Framework;
namespace Cuke4NukeExample
{
    public class HelloWorldSteps{
        private String action;
        private String subject;
        [Given("^The Action is ([A-z]*)$")]
        public void ActionIs(String action)
        {
            this.action = action;
        }
        [When("^The Subject is ([A-z]*)$")]
        public void SubjectIs(String subject)
        {
            this.subject = subject;
        }        
        [Then(@"The Greeting is ([^\.]*).")]
        public void CheckGreeting(String greeting)
        {
            Assert.AreEqual(greeting, action + ", "+subject) ;
        }
     }
}


Add a reference to NUnit.Framework.dll (from your NUnit installation) and Cuke4Nuke.Framework.dll (you’ll find it in C:\Ruby\lib\ruby\gems\1.8\gems\cuke4nuke-0.3.0\dotnet\Cuke4Nuke.Framework.dll). Now build the project again, go to the console and re-run the Cuke4Nuke command. The output should now say that the steps passed.

When it runs the feature specification, Cuke4Nuke will look for methods marked with Given, When and Then attributes that match steps by regular expression. Any capture groups in the regular expression are passed to the method as arguments (they don’t have to be Strings, you can use other .NET types as well). So, for example, the line “When The Subject is World” matches the following method:

[When("^The Subject is ([A-z]*)$")]
public void SubjectIs(String subject)
{
     this.subject = subject;
}


Our simple script will set the subject and the action and then verify the greeting using the standard NUnit assertion Assert.AreEqual. Just to see it when it fails, modify the CheckGreeting method or feature source so that they don’t match and re-run Cuke4Nuke.

Of course, for a proper project this code would talk to our domain classes but let’s keep it simple.

Build integration

We can add Cuke4Nuke as a post-build step so that all the specifications get executed after every build. Open your project .csproj file and add this just above the closing tag:

<PropertyGroup>
<PostBuildEvent>cuke4nuke $(TargetPath) $(ProjectDir)features -q 
 </PostBuildEvent>
</PropertyGroup>


You can now inspect the results of Cuke4Nuke in your output window every time a project is built.

Continuous Integration

To complete the project setup, let’s run Cucumber tests within a continuous integration environment and store test outputs next to project build results. I use TeamCity even for .NET projects, so I’ll use it in this tutorial as well. (Setting up TeamCity is outside the scope of this tutorial, but it is fairly easy to do. Grab it from jetbrains.com). TeamCity 5 should support Cucumber out of the box but I haven’t been able to make it work. Cucumber/ANT docs for TeamCity suggests that a few environment variables should do the trick for ANT/Java builds but this doesn’t work for Cuke4Nuke. The Cucumber Teamcity template uses a deprecated API and fails to build with the latest Cucumber version, and the only other blog post I found on TeamCity and Cucumber uses the same (broken) API. However, Cucumber can export a JUnit XML test report file, which is more than enough to get us nicely integrated with TeamCity (even with the previous versions). We’ll make Cucumber save the test results into the test subfolder of our project folder, and tell TeamCity to monitor that. First, let’s change the .csproj project file. Modify the PropertyGroup block you just added to the following:

  <PropertyGroup>
    <PostBuildEvent>cuke4nuke $(TargetPath) $(ProjectDir)features -q 
     -f junit -o$(ProjectDir)test</PostBuildEvent>
    <PreBuildEvent>del $(ProjectDir)test\*.xml</PreBuildEvent>
  </PropertyGroup>


This will save test output in the JUnit format (-f junit) into the test subfolder of our project directory (-o$(ProjectDir)test). It will also delete any previous test results from that folder when the build starts. Now set up your TeamCity project as normal. On the Build Runner configuration screen, select “ANT Junit” in the “XML Report Processing” section and set the import path as test/*xml (if you are working without a version control system, this will probably have to be a full path to your project folder rather than a relative path):

Everything should now be set up. You should be able to run the TeamCity build and get the “Tests passed:1″ message in TeamCity.

That’s it. Now continue writing feature specifications and implementing them in nice little iterations. Good luck! If you’re interested in this topic, you might also be interested in my new BDD with Cucumber workshops.

I'm Gojko Adzic, author of Impact Mapping and Specification by Example. My latest book is Fifty Quick Ideas to Improve Your User Stories. To learn about discounts on my books, conferences and workshops, sign up for Impact or follow me on Twitter. Join me at these conferences and workshops:

Specification by Example Workshops

Product Owner Survival Camp

Conference talks and workshops

22 thoughts on “BDD in .NET with Cucumber, Cuke4Nuke and TeamCity

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #509

  2. I’m getting a Gem::GemNotFoundException when I run the “gem install cuke4nuke”

    Richard, will the development kit install solve this?

  3. Hi Gojko. Thanks for the quick response.
    Thanks for this post, too. It has inspired me to finally try cuke4nuke. I’m looking forward to getting past this little snag.

    Yes, I did add gemcutter as instructed in the post and got confirmation that it was added to sources. However, I still get:
    ERROR: While executing gem … (Gem::GemNotFoundException)
    Could not find cuke4nuke (> 0) in any repository

    BTW installing the development kit didn’t help this issue (but you knew that :) .

    I’m running:
    ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]
    gem 0.9.4

    Any other thoughts?

  4. Problem is with my gem install. I can’t install any gems and I can’t even query gems. I’ll post back if/when I solve.

    Thanks.

  5. OK. Got it working using Ruby 1.8.6-p383 (RC1). Thanks Gojko.

    Next issue is that the modification to the .csproj file is not producing any results in the output window.

  6. Randy – Sorry you had an issue installing Cuke4Nuke. I’ve seen this a couple times with the older Ruby installer but I’m not sure why it only happens for some people. The fix is what you discovered: use the new Ruby installer, including the dev kit.

    The cukes Google group is the best place to post Cuke4Nuke questions. There are several people there who can respond, and the answers will help others who have the same issues in the future.

    Thanks,

    Richard

  7. Hi

    Great article, I have wanted to try cucumber with dot net, and having tried with Iron Ruby with little success I liked the sound of this solution.

    however everyting is installed correctly, but when I run the initial cuke4nuke bin\debug\…. etc, I get a message box saying the servier has stopped with a problem and an in error,

    any ideas, as I am new to the whole ruby enviroument, and still hacking my way around :)

    Thanks
    Duncan

  8. Getting same issue as everyone else (unable to connect to wire server is the message I get in the console session) – though tests did run first time.

    ansi.rb fix did not work on my work machine

  9. I also was getting the “unable to connect to wire server” error. I had to explicit start the server process at %RUBY_HOME%\lib\ruby\gems\1.8\gems\cuke4nuke-0.3.1\dotnet\Cuke4Nuke.Server.exe.

    Still after doing this, each time I run I get a dialog box which states, “Server has encountered a problem and needs to close.” Any way to make this go away?

  10. Hello,

    I’ve started to use SpecFlow, which, for what I’ve seen of Cuke4Nuker, 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 your scenario is limited to the class in which you are standing, it shouldn’t be a problem, as you did in your example with the “action” and “subject” variables.

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

    Thanks,
    Kevin

  11. Hi there,

    I am at step 1, installing ruby then dev kit.

    Ruby was installed under c:/ruby.

    What is the path shall I use while extract Dev kit?

    Thank you
    Jenny

  12. I just found to put devkit in c:/devkit folder.

    installed rubyinstaller – 1.9.9.p0…
    then devkit- 3.4.5-20100819-1535…
    then
    gem sources -a http://gemcutter.org/
    gem install cuke4nuke
    gem install win32console

    When I run cuke4nuke, it displays an error “missing msvcrt-ruby18.dll”

    I installed ruby18626-26 to a different folder “ruby186″ on C drive then copy the missing dll to Ruby/bin folder.

    Now when I run cuke4nuke, I get a message:
    “You may have encountered a bug in the Ruby interpreter or extension Libraries.
    Bug reports are welcome.
    For details:http://www.ruby-lang.org/butreport.html

    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application’s support team for more information.”

  13. Hi Gojko.
    Thanks very much for this article.
    I have a problem, there is a folder named “support”, in cucumber examples, there are two ruby files there: env.rb, config.rb.
    I can define global variable and constant here, but in cuke4nuke, when I built a solution, and run it in command, these files can’t be used anymore, what can I do? thanks!

  14. Thank for your answer!
    One more question :)

    as we know, we can call another step in the step, e.g:
    Given I goto to Google page
    Given I open the browser
    end

    the problem is: if there is a table in the second step, how can I pass the table to first step and use it? Have you got this problem? thanks very much!

  15. I have same problems as Jenny :-(
    When I run cuke4nuke, it displays an error “missing msvcrt-ruby18.dll”
    How you resole that?
    A.

  16. If you get the “missing msvcrt-ruby18.dl” error you must uninstall json and reinstall an earlier version:

    gem uninstall json json_pure –all

    (You may get an error if json_pure is not installed, which you can ignore, if you are being asked to remove executables:
    edit_json.rb, prettify_json.rb
    you should answer Y(es))

    Then install version 1.4.6 of json:

    gem install json –platform=ruby -v 1.4.6

    That helped me to get rid of the error.

  17. Gojko,

    Have you managed to generate an junit xml with the junit formatter? I’ve noticed that even in your git project where all examples are stored you didn’t include the ‘-f junit’ option in .NET HelloCucumber project. I must say that I’m struggling a lot with this.
    Each time I use the following command:
    cuke4nuke F:\Cuke4NukeExample\Cuke4NukeExample\bin\Debug\Cuke4NukeExample.dl
    l F:\Cuke4NukeExample\Cuke4NukeExample\features -q -f junit -oF:\Cuke4NukeExampl
    e\Cuke4NukeExample\test
    I’m getting:
    Invalid argument – F:\Cuke4NukeExample\Cuke4NukeExample\test/TEST-F:\Cuke4NukeEx
    ample\Cuke4NukeExample\features\basic.xml (Errno::EINVAL)
    Pardon me, but what the heck? Why does the junit formatter try to contact the path where features are held with the test output directory? Do you know how to resolve this?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>