Testing .Net code with Cucumber and IronRuby

As promised, this is the culmination of this trilogy. The previous two posts were a jump-start on Cucumber to test Ruby code. Next I moved towards using Cucumber's plain text stories to test .Net code.Aslak Hellesoy has a wiki-post on how to do this ; however I found that you get eaten and spat out by a lot of IronRuby dragons along the way. So hold on..

1. Install the new DLR

First up install .Net Framework 4.0 (I have Beta1) - this has the new Dynamic Language Runtime (DLR) that makes things like IronRuby and IronPython possible.

2. Get the latest IronRuby release

Next we need to get IronRuby as a zip. Extract it to say d:\ironruby-0.9.0 Add the path to the bin folder to your PATH environment variable to avoiding lengthy paths. Drop to a command shell, type 'ir' to invoke the interactive IronRuby console. Type something simple to test if it works. It should.
>>>puts "Hello IronRuby"

3. Dragons ahead. Use diversion

But I hit a snag with this version of IronRuby, which had A BUG.

  • So I had to get the latest (8 Sep 2009 master to be precise) version of the source from the github repository to overcome that. You can download it as a zip or use git as you prefer. I got the zip
    ironruby-ironruby-90cdda82fd60f4b7e6d7d940501c586d55954466.zip (Could have used a shorter name)

  • Extract it to say d:\ir-src
    I hit a few path-too-long errors during extraction. Just keep skipping them. I think it's because of the rather large alphanumeric string which is the name of the top-level folder.

  • Once extracted, navigate to D:\ir-src\ironruby-ironruby-90cdda82fd60f4b7e6d7d940501c586d55954466\Merlin\Main\Languages\Ruby
    and open Ruby.sln in VS2008 (I have Dev Edition of VSTS.. Although it should build in VS Express Editions as per the docs - I couldn't get the solution to open in it.)
    Build Solution. At the end of it you should find the built binaries in

  • Rename that directory with the huge name to something like "ir".

  • Copy all built binaries and overwrite the ones from the 0.9.0 release's bin folder i.e. D:\ironruby-0.9.0\bin.

  • Open ir.exe.config in the same folder and update the Library paths element to the proper paths to folders within your ir-src folder. 'Handle with extreme care' or you'll lose hours chasing error messages. It should read
    Path#1 - D:\ir-src\ir\Merlin\Main\Languages\ (NOT D:\ir-src\ir\Merlin\External.LCA_RESTRICTED\Languages)
    Path#2 & #3 - D:\ir-src\ir\Merlin\External.LCA_RESTRICTED

    My xml looks like
    <set language="Ruby" option="LibraryPaths" 
    uages\Ruby\redist-libs\ruby\1.8\" />

4. Wrapper script ICucumber

Lastly we need a wrapper script to invoke cucumber with Ironruby. Create a file called icucumber.bat under your Ruby bin folder i.e. D:\Ruby\bin\icucumber.bat with the following text.

REM Update with appropriate values for GEM_PATH, Ruby bin and the path to ir.exe
REM This is to tell IronRuby where to find gems.
SET GEM_PATH=d:\ruby\lib\ruby\gems\1.8
"D:\ironruby-0.9.0\bin\ir.exe" -D -X:ExceptionDetail "d:\ruby\bin\cucumber" %*

5. Back to our example from the previous two posts.
The .feature file stays unchanged.
Delete c:\cukes\dot_net_features\support\BowlingGame.rb ; since we're going to implement the same in C# this time around as

namespace CukesDemo
public class BowlingGame
public void roll(int pins_knocked_down)
Score += pins_knocked_down;

public int Score
get; set;
public bool Over
get { return false; }

Also create a small batch file to compile it to a DLL (Assumes csharp compiler is on the PATH).

csc /t:library /out:bin/BowlingGame.dll bowling_game.cs

Finally back to our step definitions to check the glue. Four changes needed - explained in comments.

# CHANGE 1 : Add bin folder to load-path
$:.unshift(File.dirname(__FILE__) + '/../support/bin')
# CHANGE 2 : Get BowlingGame.dll
require 'BowlingGame'

Given /^I am starting a new game$/ do
# CHANGE 3 : Use Namespace::ClassName.new
@game = CukesDemo::BowlingGame.new

When /^I roll (\d+) gutter balls$/ do |count|

Then /^the score should be (\d+)$/ do |expected_score|
@game.score.should == expected_score.to_i

Then /^the game should be over$/ do
# CHANGE 4 : be_over passes even if Over returns false. Don't know what is the equiv of over?

in .Net
#~ @game.should be_over == true
@game.over.should == true

When /^my rolls are (.*)$/ do |rolls|
rolls.split(' ').each{|roll|

Now for the grand finale, run Cucumber to verify our .Net DLL via IronRuby !!!


No comments:

Post a Comment