<< 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:
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):
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).
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:
There they are! Only because the function names have been rubyized, they have become
add_card and
eval_score.
Let try playing a hand:
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:
Save that and we can run our cucumber test again:
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:
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/