Friday, August 6, 2010

Testing C# with RSpec and Ruby

Why would you want to do this?

Simple: More readability, less ceremony. This means you can write your tests faster, update them faster, understand them faster, and generally just be happier!

Why would you NOT want to do this?

Simple: Microsoft just dropped support for it...

I just spent the last week working on this stuff, so I'm just a little bit pissed at my timing. For example, this whole blog post was already written! Whether we should allow this to prevent us from considering using IronRuby is whole different issue. I think I'll just have to wait and see what happens before making that decision.

That said...

How do you do it?

I have some sample code you can browse to help you get started at

I'm working with IronRuby on .NET 4.0 and rspec 1.3.0.  Know that if your versions are different, stuff may work differently.

Setting up the environment:
  1. Install IronRuby (install it in C: instead of Program Files if you don't want to mess with your path to get gems working later on)
  2. igem install rspec
  3. optionally: igem install rake
  4. optionally: igem install caricature
  5. optionally: igem install flexmock
Starting to test your .NET code:
  1. Add a Specs folder (call it whatever you want) in your project's main folder (or wherever)
  2. Create spec_helper.rb in the Specs folder, more on this in a bit
  3. Create an examples folder (call it whatever you want)
  4. Add your test files in the examples folder
  5. All of your tests should require 'spec_helper'
Executing your tests:

You can execute one test at a time by executing this command in the Specs folder:

ir -S spec examples\first_test.rb

To execute all the tests you can write a rakefile like this:

require 'rake'
require 'spec/rake/spectask'

desc "Runs all examples"'examples') do |t|
t.spec_files = FileList['examples/**/*.rb']

That last bit works great, unless you're executing IronRuby with the PrivateBinding flag turned on... More on that later.

More on spec_helper.rb

If you've never played with ruby before, this may be slightly weird.  All of your tests will require 'spec_helper'.  This effectively executes the code in spec_helper.rb (but only 1 time) allowing us to centralize configuration required by our tests, or even define helpful helper methods.

There are two things you should definitely do here: tell Ruby where to find your .NET assemblies and require common dependencies all tests will need.

Telling Ruby where to find your .NET assemblies is similar to telling cmd what directories to search by adding to your PATH variable.  You do this in ruby by appending to the $: magic variable (aliased $LOAD_PATH):
$: << '../Src/Model/Model/bin/Debug'
There are other ways to find your .NET assembly without modifying the load path, but I kind of like this approach.

Common stuff you'll want to require includes rubygems, spec, and your .NET dll you're trying to test:
require 'rubygems'
require 'spec'
require 'Model.dll'

More on PrivateBinding
If you're writing DDD style code in .NET, you probably have internal constructors and things which you need to be able to execute with your tests. If you were testing with NUnit, you'd setup your test assembly as a friend assembly of the assembly under test. assembly.

You can't do this when you're testing with IronRuby because there IS no assembly. So instead, you have to invoke IronRuby with the PrivateBinding flag as follows:
ir -X:PrivateBinding ...

This works great for accessing your internals or privates in .NET. But sadly, there is currently a bug somewhere that causes rake to break. I posted to StackOverflow here but haven't found a solution yet. So be aware of that.