Specification Testing in .NET using Ruby

Not long ago, I posted a big fat blat of information from my investigation in trying to get Ruby based spec testing integrated with .NET. In this post, I make some sense of all that content and (more importantly) drop a sample of taking advantage of this. (nb: This post is essentially a direct-rip of an internal document I created for this purpose)


The purpose of this page is to run through a process which will ultimately allow the reader (thats you) to write Ruby based specifications for your .NET code.


Why would you want to do this? The intended purpose for this practice is to gain the most benefit when doing BDD. Trying to do BDD in C# results in a lot of syntactical noise in the code which distracts from the goal of having clear, readable specifcations of how the intended function should behave. Additionally, any traditional C# BDD toolset requires the specifications to be statically compiled into a test binary in order to be executed. The advantage of using Ruby is that the scripted nature of the language allows physical (as well as logical) separation of speficiations from code, opening up the realm of possibility that specifications are written by non-technical folk. Furthermore, the Ruby syntax lends itself to building DSLs perfect for the purpose of allowing clean, almost human-readable code.

Scope of investigation

The investigation work preceding this post was set 3 goals:

  • Determine the viability of using Cucumber as an automated feature verification utility
  • Determine the viability of using RSpec as an automated specification verification utility
  • Determine the viability of using IronRuby as conduit to allow Ruby specificaitons to execute against compiled C# code. (applicability to any other CLR-supported language is then assumed).

Investigation results

The results of the investigation showed that:

  • RSpec is currently not supported on IronRuby due to a number of bugs in the IronRuby project. (Based upon a discussion with @jschementi and this article (toward the bottom))
  • Accordingly, Cucumber is currently not supported on IronRuby due to it using RSpec internally (explained onthe ruby forums)
  • The IronRuby team have worked to incorporate support for a more lean specification testing tool MSpec which is very similar in syntax to RSpec, but not as functionally complete.
  • MSpec will work with IronRuby to write Ruby based specifications to verify .NET compiled applications.

What tools are we using?

Based on the results of the investigation, the best way to approach this method of testing is to use the MSpec library to write specifications against C# code, execute them using IronRuby and in future, once IronRuby is more stable we can look to migrating over to cucumber for feature-style verification on top of M/RSpec.


RubyGems is a package which allows you to download ruby components and utilities (known as Gems). The default RubyGems package which comes with the one-click installer might be outdated when you download it, so the best thing to do here is to update RubyGems to the latest version

gem update –system

In the event you’re behind a company firewall, or you need to use an HTTP proxy for whatever reason, you need to tell the GEM command to use the http proxy as it doesn’t honour your default internet options. Substitute the server and port where appropriate and then run the gem update:

SET HTTP_PROXY=http://your.proxy.server:3128

You’re now minty fresh with the latest RubyGem package.

IronRuby (IR)

Go and download the latest release of the IronRuby project from ironruby.net. The current “official” pre-release release is v0.3, and it doesn’t have any installer. To “install”, make sure you extract the contents to the location


This is the standard installation location for IR. Once there, it’s recommended that you update your system path to include the path your IR’s bin folder.

Setting PATH Environment for IronRuby

Setting PATH Environment for IronRuby

Required Gems

We now get to the part where you need to install some of the gems required for specification testing. As mentioned at the start, RSpec and Cucumber isn’t 100% working with IR just yet, however it’s worthwhile installing them anyway to test things are working as expected and whatnot.

gem install mspec
gem install cucumber
gem install win32console
##gem install rspec
##gem install hoe

The last 2 should automatically be installed when you install cucumber as they’re dependencies, but if they don’t make sure you install them! If you really want to keep it lean you can get away with just mspec and none of the others.

Now the standard install of IR has its own repository of gems which can be managed thorugh IR’s igem utility. The reason we don’t use IR’s gem utility to install mspec is because mspec is a pretty special script which (basically) allows us to tell it which ruby interpreter we wish to use for running tests (explanation, thanks to @jredville). The neato thing here is that we then don’t need to install mspec speficially for IR, we can repurpose the MRI’s version.

Testing it out

Now that all the major stuff is installed lets test it out by creating a simple app in C# and write a specification in Ruby to verify its behaviour. Create a new folder to save the source files in.

using System;

namespace HelloWorld
    public class HelloClass
        public string SayHello()
            return "Hello from C#";

Here we have a class which returns a string when the method SayHello() is invoked.

require "mspec"
require "HelloWorld.dll"

describe "the hello dot net app" do 
	before do 
		@app = HelloWorld::HelloClass.new

	it "should say hello from c#" do 
		@app.say_hello.to_s.should == "Hello from C#"

This is our specification for the behaviour of the application.

To compile the C# class, open up a Visual Studio Command Prompt, CD to the source directory and type

csc /target:library /out:HelloWorld.dll HelloWorld.cs

…and now to run this puppy:

mspec -t c:ironrubybinir.exe sayhello_spec.rb

Here, we are invoking the mspec ruby script and passing two arguments. The first -t c:ironrubybinir.exe tells the ruby script that we with to execute the mspec specifications using a different Ruby interpreter to MRI. The interpreter we want to use in this case is IronRuby. The second argument tells it which spec we’re running. When mspec runs, it finds the -t argument and hands-off execution of the spec to another instance of mspec executing under IronRuby. This gives us the flexibility of being able to execute standard ruby specs and also calling out to IronRuby for .NET interop if needed.

The observant of you might notice that the call to @app.say_hello has a to_s chained afterward. IronRuby will return a ClrString as the object type when the interop call returns a CLR type string. the CLR’s ClrString and Ruby’s string are not interchangeable. You need to call to_s on the ClrString to treat it like a ruby string. This behaviour is at least explained, albeit I need to dig deeper to understand why they couldn’t have an implicit cast operator (or dynamic language equivalent thereof).

One thing that’s important to note is that although i’ve dropped a few source files without too much explanation, you would actually build this up iteratively using the same TDD testing style you’ve always been used to. In fact, this form of specification testing makes test-first easier to do.

Further work

This article gives a straightforward overview of how to begin testing C# code with Ruby but it doesn’t go all the way.

  • Ideally we would like to use Cucumber for automated feature acceptance test verification. Unfortunately the current build of IronRuby doesn’t work with Cucumber and RSpec but there should be ways to get the current IR implementation to work with a few tweaks.
  • Need to define and configure a standard project skeleton such that you don’t need to download and extract IR in order to get the system working. In a perfect situation, we could download only the source for the software without requiring any dependencies installed (including ruby!).

1 comment

Leave a Reply

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