Geeks With Blogs
Greg Malcolm Everything but the Perl
<< Part 2 – A quick look at IronRuby

Gambling with Cucumbers

In part 2 we demonstrated how we can mix .NET and Ruby though IronRuby. The question is, why would you want to do that? It is probably easier to stick with one language for most projects. Why combine them?

The problem with BDD in .NET

One area where Ruby currently has a clear advantage over.NET is in the realms of Behavioral Driven Development (BDD).

You can write Unit Tests and Integration Tests in .NET just fine, but what about when you want to make tests based on actual user stories?  Specifications written as word documents and UML diagrams have a tendency to evolve separately to the actual product. If you could replace the specifications with human readable tests specifications it could easier to keep the product’s functional requirements in sync with the actual implementation.

The problem with this is that not everyone involved with the product is necessarily going to be a programmer. For example, this NUnit test a poker hand that should make up “One Pair”:

[TestFixture]
public class DemoTests
{
    Hand _hand;

    [SetUp]
    public void SetUp()
    {
        _hand = new Hand();
    }

    [Test]
    public void Should_show_one_pair_for_3c_3s_Jc_9d_As()
    {
        _hand.AddCard("3 clubs");
        _hand.AddCard("3 spades");
        _hand.AddCard("J clubs");
        _hand.AddCard("9 diamonds");
        _hand.AddCard("A spades");
        Assert.AreEqual("One Pair" , _hand.EvalScore());
    }

    .
    .
    .
}

This makes plenty of sense to developers, not so much to business professionals. And this is a relatively readable test, what if theres mocking and other distractions?

Now compare that with the popular Ruby BDD framework, RSpec:

# hand_spec.rb

require 'IronPoker'

describe Hand do
  it "show a score of 'One Pair' if player has " +
  "3 Clubs, 3 Spades, J Clubs, 9 Diamonds and A Spades" do
    20.times { bowling.hit(0) }
    bowling.score.should == 0
   
    hand = IronPoker::Hand.new
    hand.add_card "3 Clubs"
    hand.add_card "3 Spades"
    hand.add_card "J Clubs"
    hand.add_card "9 Diamonds"
    hand.add_card "A Spades"
   
    score = hand.eval_score
    score.should = "One Pair"  
  end
end

Much cleaner!

And you can also use command line tools to generate reports:

$ spec hand_spec.rb --format specdoc

Hand
- show a score of 'One Pair' if player has 3 Clubs, 3 Spades, J Clubs, 9 Diamonds and
  A Spades

Finished in 0.007534 seconds

There have been attempts at creating similar frameworks for .NET, but there are syntactical constraints that make it difficult to keep the readability. For example, my favorite .NET BDD framework is MSpec (also known as Machine Spec). Here is what an MSpec spec looks like:

// machine.spec (mspec) sample

using IronPoker;

[Description]
public class Player_showing_their_hand
{
    static Hand _hand;

    Context before_each = () =>
    {
        _hand = new _Hand();
    };

    When 3_clubs_and_3_spades_and_J_clubs_and_9_clubs_and_A_Spades_are_dealt = () =>
    {
        _hand.AddCard("3 clubs");
        _hand.AddCard("3 spades");
        _hand.AddCard("J clubs");
        _hand.AddCard("9 diamonds");
        _hand.AddCard("A spades");

        _result = _hand.EvalScore();
    };

    It should_show_a_score_of_One_Pair = () =>
    {
        _result.ShouldEqual("One Pair");
    };
}

Sure it looks a bit like RSpec, but notice how the When…It… descriptions have to be separated by underscores, and the use of the unsightly “= () =>” lambda syntax at the end of each clause? There are other BDD frameworks, but they all have to make compromises somwhere. (In fairness to MSpec, it does at least have a tool which generates very nice html RSpec style reports though!).


Cucumber, Finally!

As nice as RSpec is, we can do even better when it comes to turning user stories into tests. Cucumber is an RSpec extension that lets you write tests like this:

Feature: Player shows their hand
  In order to finish the round
  The player
  Needs to show their hand

Scenario Outline: Play is dealt a card
  Given I have a <card_1> in my hand
  And I have a <card_2> in my hand
  And I have a <card_3> in my hand
  And I have a <card_4> in my hand
  And I have a <card_5> in my hand
  When I am dealt a card
  Then the result should be <output> on the screen

Examples:
  |   card_1   |   card_2   |   card_3   |   card_4   |   card_5   |      output     |
  | 3 Clubs    | 3 Spades   | J Clubs    | 9 Diamonds | 3 Spades   | One Pair        |


Makes sense, right? The first section, “Feature” describes in plain English the story and use case. The scenario is described in the what appers to be plain English, but actual confirms to a “Given… When… Then”  structure. And final the table of examples directly correlates to the parts of the Scenario bracketed names (card_1, card_2 etc).

Because part Cucumber is part of RSpec this means it also implemented in Ruby. Sounds like a job for IronRuby!

Lets try it out!

IronPoker tutorial

For this demonstration we are going to try out Cucumber on an incomplete .NET application application I’m calling “IronPoker”. I got as far as writing the code to analyse poker hands written TDD style using NUnit. Lets switch and let Cucumber have a go!

The IronPoker code is in  github:


You can either checkout the code using Git, or click on the Download button to retrieve the it  in the form of a .zip file. The solution file is in Visual Studio 2008 format, but don’t worry if you don’t have it, we are going to work with Cucumber from the windows command interpreter.

Incidentally if you build and running IronPoker from Visual Studio there is not much to see there. The executable is a stub:
 
IronPoker Stub App Screenshot

The bulk of code currently written is all in the ‘IronRuby’ class library. Its just logic to calculate scores. Feel free to poke around in ‘IronPoker.Tests’ if you want to get a feel for it does. But we’re here for the cucumber, right? Open up a command prompt, navigate to this folder:

IronPoker\src\IronPoker.Cucumber

and we’ll run the cucumber test found in the subfolder:

.\Features\PlayHand.Feature

by running:

icucumber.bat Features

Note: if you start seeing “[36” spread liberally through the output, this means that the console colors do not work in your version of ruby. I have the same problem. See the Cucumber installation comment in Step 1 of this guide for details on how to turn it off.

Anyway, here are the results (in boring monochrome):
 
1st Cucumber Test Results Screenshot

Cucumber parsed the “feature” file, but didn’t find an implementation. Generously, it hass given us some code to get started with!

We have an implementation file already, but it is empty. It is here:
 
.\Features\steps\ironpoker_steps.rb

Copy and paste the implementation so far. (Copy and paste is available from the top left menu of the command window).
 
Initial Implementation Screenshot

As you may have gathered, this is ruby code. Next we need to figure out how to drive our IronPoker .NET code from IronRuby. This is where the “IIRB” tool comes in handy! (Reminder, its accessed by running “iirb.bat” from the windows command interpreter).

First off we need access to IronPoker.dll, which can be built from the “IronPoker” class library. You don’t need build it though because a copy of it is already in the IronRuby.cucumber folder, just to keep things simple! We can load it with:

require 'IronPoker'

Next we need to test the IronPoker.Hand class, as found in IronRuby\Hand.cs. So lets make an instance of it:

hand = IronPoker::Hand.new

Which of course is the same as saying “var hand = new IronPoker.Hand()” in C#.

Remember that NUnit sample we looked at earlier? We’re looking to do the same thing with Cucumber. So we need access to AddCard() and EvalScore() methods to run our tests. We can inspect which methods are available to us by running method called methods. Every ruby object has this:

Hand.methods Screenshot 

There they are! Only because the function names have been rubyized, they have become add_card and eval_score.

Let try playing a hand:
 
Straight Flush in IIRB Screenshot

Yep, Ace, 2, 3 ,4 and 5 of spades is indeed a ‘Straight Flush’.

Now we just have to do something similar for Cucumber. Time to go back to implementing ironpoker_steps.rb. First off stick this at the top of the code before the Given statements:

require 'IronPoker' # IronPoker.dll

Before do
  @hand = IronPoker::Hand.new
end

The Before clause is the equivalent of the “SetUp” method in typical unit testing frameworks. In other words, It is the function that gets called before each test. In this case the “hand” object is a member instance rather than a local instance so it has the extra @ at the front.

Next we need to to call add_card for each of the 5 given statements. We can actually reduce it down to one statement though thanks to regular expression:

Given /^I have a (.*) in my hand$/ do |c|
  # c = (.*)

  @hand.add_card c
end

In ruby, regular expressions are encapsulated between forward slashes. So we just have one given statement with a regular expression wildcard (.*) on the part that changes, the card descriptions. The body of the Given block assign the text from the wildcard to the variable “c” and uses it as the argument for “@hand.add_card”.

This will be the When block:

When /I am dealt a card/ do
  @result = @hand.eval_score
end

Which is saying that when the player receives a card it will be evaluated and stored in @result. In the case of the test, this applies for when the player has all 5 cards.

Finally in the Then block we evaluate whether or not the conditions of the test are met:

Then /the result should be (.*) on the screen/ do |score|
  @result.should == score
end

So @result is compared to the wildcard (which was assigned to “score”). So its roughly the same as an Assert in a unit testing framework.

Put it all together and we have:
 
Implemented Tests Screenshot

Save that and we can run our cucumber test again:

 
Failed Test Screenshot

The test completed! Only problem is  the result was “Three of a kind” instead of “One pair”. It actually is a Three of a kind, so the test is wrong!

Easily fixed, change one of the 3s to an A and it should pass.

Also why not add some more examples to the examples talbe in ‘PlayHand.Feature’? Try changing the examples section to this:

    Examples:
      |   card_1   |   card_2   |   card_3   |   card_4   |   card_5   |      output     |
      | 3 Clubs    | 3 Spades   | J Clubs    | 9 Diamonds | A Spades   | One Pair        |
      | 9 Diamonds | J Diamonds | Q Diamonds | K Diamonds | A Diamonds | Royal Flush     |
      | 8 Spades   | J Diamonds | 8 Diamonds | K Spades   | 8 Hearts   | Three of a Kind |
      | 8 Spades   | J Spades   | 8 Spades   | K Spades   | 8 Spades   | Flush           |
      | 2 Spades   | 2 Diamonds | 8 Diamonds | 2 Clubs    | 2 Hearts   | Four of a Kind  |
      | A Hearts   | 2 Diamonds | 3 Spades   | 4 Clubs    | 5 Spades   | Straight        |
      | 9 Diamonds | A Hearts   | 9 Clubs    | A Spades   | A Hearts   | Full House      |
      | 4 Hearts   | 5 Hearts   | 6 Hearts   | 7 Hearts   | 8 Hearts   | Straight Flush  |
      | A Spades   | 4 Diamonds | 5 Diamonds | 9 Diamonds | 8 Diamonds | High Card       |
      | A Spades   | 4 Diamonds | A Diamonds | 4 Clubs    | 8 Clubs    | Two Pair        |

Giving us:

 Completed Tests Screenshot

And that’s a wrap! (I would say "cucumber wrap" but there are Laws...)


Reference Sources

These are some of the sites which I used to research the tutorial, and a few more that you may find helpful:

Installation

Ruby - http://www.ruby-lang.org/
IronRuby - http://ironruby.net
Cucumber - http://wiki.github.com/aslakhellesoy/cucumber/ironruby-and-net


IIRB/DLR

http://msdn.microsoft.com/en-us/magazine/dd434651.aspx
http://silverlight.net/content/samples/sl2/dlrconsole/index.html


TDD/BDD

NUnit - http://www.nunit.org/index.php
Machine Spec - http://codebetter.com/blogs/aaron.jensen/archive/2008/05/08/introducing-machine-specifications-or-mspec-for-short.aspx
RSpec - http://rspec.info/
Cucumber - http://cukes.info/ Posted on Thursday, November 5, 2009 8:32 PM | Back to top


Comments on this post: IronRuby and Cucumber - Cucumber Tutorial (Part 3 of 3)

# re: IronRuby and Cucumber - Cucumber Tutorial (Part 3 of 3)
Requesting Gravatar...
Excellent material! I have also written articles and created screencasts on IronRuby, Cucumber, Spec etc. You can check out the articles using the link below:

http://www.highoncoding.com/Categories/39_IronRuby.aspx

Videos are available using the link below:
http://highoncoding.com/Categories/22_Videos.aspx
Left by Mohammad Azam on Nov 06, 2009 10:37 AM

Your comment:
 (will show your gravatar)


Copyright © Greg Malcolm | Powered by: GeeksWithBlogs.net