Integrating nBehave with nUnit, MbUnit or Gallio

On a lot of testing frameworks/runners I read   integration. But I found no examples. But then it just came to me it’s actually very very simple. So after banging my head against the wall a few times and then a few times more for being stupid, I thought I should share this with others. Please let me know that you found this helpful so I feel less stupid.

Let’s start with a specification example for a repository service:

[Theme("Storing and Retrieving Data Objects from the repository.")]
public class RepositorySpecs
{
    [Story]
    public void StoreObjectInRepository()
    {
        Story storeObjectStory = 
		new Story("Store and retrieve an object in the repository");

        storeObjectStory.AsA("service in the platform")
                        .IWant("to persist data")
                        .SoThat("I can retrieve this later");

        IRepository repository = null;
        object dto = null;

        storeObjectStory.WithScenario("a flat data object whitout IStorable")
            .Given("the data object is a $type",
		"singleLevelDto",
		dtoType => { dto = DtoFactory.GenerateDto(dtoType); })
            .And("a IRepository service",
		() => repository = Service.Get<IRepository>())
            .When("I store the object under $id and the default datastore",
		"SimpleDtoTest",
		objectId => { repository.Store(string.Empty, objectId, dto); })
            .Then("I should be able to retrieve it by supplying $id and the type",
		"SimpleDtoTest",
		objectId => { repository
		    .Retrieve<SingleLevelSimpleDto>(string.Empty, objectId)
		    .PropertyValuesAreEqual(dto); });
    }
}

We can easily change the specification in an test and still keep the specification descriptive format. Let’s start by adding the following using statements to the top of the file:

using That = NUnit.Framework.TestAttribute;
using Should = NUnit.Framework.DescriptionAttribute;
using Context = NUnit.Framework.TestFixtureAttribute;
using Specification = NUnit.Framework.TestAttribute;
using Concerning = NUnit.Framework.CategoryAttribute;

After using these attributes our example now looks like this:

[Theme("Storing and Retrieving Data Objects from the repository."),
 Context,
 Concerning("IRepository")]
public class RepositorySpecs
{
    [Story, That, Should("Store an Object in the repository")]
    public void StoreObjectInRepository() 
    { 
        Story storeObjectStory = new Story("Store and retrieve an object in the repository"); 

        storeObjectStory.AsA("service in the platform") 

This is now a fully functioning and valid NUnit test, recognized by resharper (if you’re not using this tool you are really missing out on productivity).

resharper example

Of course NUnit recognizes it too:

image

There are still two things that bug me:

  • I am duplicating the text in the Should attribute and the Story constructor.
  • you miss out on a lot of the BDD output. But that’s what dryrun is for I suppose.

But for now I’ll be able to live with both since I can easily debug from within visual studio (I know I am easy to please :) )

Tags: , , , , , , ,

BDD with nbehave tips

While using nBehave on projects especially those where we collaborated with external partners I created/shared the following list of guidelines/tips which might save you some time too. So here I am sharing it to a broader audience… maybe :)

1. All declarations/instantiations must be placed after the narrative
2. All code that can fail must be inside an actionstep delegate or lambda
3. How to execute and debug using nBehave Console Runner
4. Improving execution and debugging by integrating with nUnit

All declarations/instantiations must be placed after the narrative

The first two solve the same problem. When code fails that’s not inside an actionstep it is unhandled (especially with the nbehaverunner, look at 4 for a different runner) and the whole thing just stops with an exception. What’s even worse invalid/incomplete xml is written that will break any xslt transformation or processing which I found out the hard way while maintaining a CI (). How to integrate nBehave (or rather how I integrated it) with Hudson is worth a post on it’s ownn that will follow.

uses the Story class to execute and listen to output of the specification. A very important consequence is that if code that is not part of an actionstep (inside a lambda or delegate as a parameter of an actionstep) the complete test fails with no or invalid output.

A lot of us would write a spec in this way (since we are used to put our declarations at the beginning of a code block:

IRepository repository = Service.Get<IRepository>();

Story storeObjectStory = new Story("Store and retrieve an object in the repository");

When the Service.Get fails the story will never be created and we have no output on why or which test failed.

Our first guideline is to move all declarations past the story narrative. We created a modified nBehave runner build that produces valid output even when the code throws an exception (if you’re interested let me know).

Let's look at our modified example:

Story storeObjectStory = new Story("Store and retrieve an object in the repository");

storeObjectStory.AsA("service in the platform")
                                .IWant("to persist data")
                                .SoThat("I can retrieve this later");

IRepository repository = Service.Get<IRepository>();

storeObjectStory.WithScenario("the single level data object does not implement IStorable")

All code that can fail must be inside an actionstep delegate or lambda

nBehave will nicely catch and report exceptions in code that are part of an actionstep. Code failing outside an actionstep will result in unexpected behaviour.

To improve our previous example we should place the initialization of the repository component inside an actionstep. Since it is part of the setup the appropriate place is the “Given”-actionstep (or a subsequent “And”-actionstep).

Story storeObjectStory = new Story("Store and retrieve an object in the repository");

storeObjectStory.AsA("service in the platform")
                                .IWant("to persist data")
                                .SoThat("I can retrieve this later");

IRepository repository = null;
object dto = null;

storeObjectStory.WithScenario("the single level data object does not implement IStorable")
        .Given("the data object is a $type", "singleLevelDto", dtoType => { dto = DtoFactory.GenerateDto(dtoType); })
        .And("a IRepository service", () => repository = Service.Get<IRepository>())
        .When("I store the object under $id and the default datastore", "SimpleDtoTest", objectId => { repository.Store(string.Empty, objectId, dto); })
        .Then("I should be able to retrieve it by supplying $id and the type", "SimpleDtoTest", objectId => { repository.Retrieve<SingleLevelSimpleDto>(string.Empty, objectId).PropertyValuesAreEqual(dto); });

 

How to execute and debug using nBehave Console Runner

A major pain point of nBehave is the difficulty of testing it on a local machine. One way of executing these is by creating or re-using the batch scripts used by your CI-server (in our case it’s hudson). We use a tools/scripts folder in our source tree.

We have a nBehaveRunAll.cmd which will execute all component specs. It accepts an output directory parameter relative to the different project folders. By default it uses the output of the debug (anycpu) configuarion (the configuration chosen in visual studio). The following example shows how to specify the release configuration:

... >Tools\Scripts\nBehaveRunAll.cmd bin\Release 

To debug you can specify the nbehave console runner in your project properties:

image

In Start External Program fill in the path to the NBehave console runner.

The command line arguments consist of 2 arguments:

  • The assembly you want to run
  • xml=<xml output> parameter. This one is important. Without it you are not executing the tests.

Now you can set breakpoints and start debugging by pressing F5 :)

Keep in mind that these settings are configuration dependent! This means that whenever you change the build configuration (for instance to release or x86 instead of any cpu) you’ll need to reenter these values. Is there no better way you ask? Read on to find out how…

Improving execution and debugging by integrating with NUnit

The above is fine if you are a build server but a lot of developers use resharper or the (or the Galio Icarus) GUI to run and debug tests. Changing my specs into this made such an impact on the usage of NBehave with our partners, that I created a seperate blog post explaining this. Before a lot of the partners “forgot” to execute, update or correct the executable specifications (BDD tests) because they perceived them as being hard and time consuming. By changing them into NUnit tests this problem was solved.

Tags: , , , , , , , ,