Updates to NBehave


What happened to NSpec?

I am not sure if all of you know but the NBehave project consolidated with the NSpec project a while back, since then we have been pretty silent about what we are doing because we wanted to give the community something they could simply drop in and not be to evasive in its implementation. Meaning we didn’t want you to have to learn how to use yet another runner.

What we decided is that NSpec did a lot of cool things but at its heart was an assertion engine. We contemplated if we really wanted to go down the path of creating a whole new assertion engine. This is where Andrew Stopford’s and Jeff Brown’s MbUnit 3.0 Gallio engine come in.

 

“The Gallio platform is an open, extensible, and neutral system that provides a common object model, runtime services and tools (such as test runners) that may be leveraged by any number of test frameworks. In this vision of the world, MbUnit v3 itself is simply another test framework plugin with the same status as any other.”

NBehave will utilize the Gallio extensible test framework and employ as many of the BDD idioms as we can manage to squeeze in.

This will enable us to offer:

  • To use any of the 7 current Gallio test runners, including console, GUI, MSBuild, NAnt, PowerShell, ReSharper and TD.Net plus any new ones that are developed.
  • CCNet integration and most anything else that’s built around Gallio
  • NBehave with Gallio as a bundle.

Pretty cool right? Well as you can imagine this has been ongoing trial an error but the good part is we are working with the Gallio dudes to get something out there.

So does that mean I have to wait to use BDD then? No…

We wanted to give you all something now.

One of the more important constructs of BDD is that we are now specifying how our code should behave under a governed context. Whether that context is story governed or system governed is particular to the situation that is eliciting the invocation. Laymen response it is not just about stories and acceptance testing.

BDD is about creating a reentrant code base that can be understood by development teams working together to create great software. You should be able to perform a cursory glance at you specifications and understand intentions and expected behavior. The difficult part is that this is going to require the same type of self discipline that TDD fostered.

So how do you take advantage of this now?

Well the current repository on Google Code has several features that we think the community can take advantage of now. Thanks go out to David Laribee and JP Boodhoo for the help with the base spec fixture.

Here is a list of some of the features we have completed and are working towards.

  • · NUnitSpecBase – Done
  • · MbUnitSpecBase – Done
  • · NUnit assertion extensions – Done
  • · MbUnit assertion extensions – Done
  • · Automocking Container – Done
  • · Create MSTest assertion extensions (April 1st)
  • · Create xUnit assertion extensions (April 1st)
  • · TestDriven.NET integration (April 1st)
  • · XML output for stories (April 1st)
  • · XSLT for XML story runner output (April 1st)

So how do I use these new features?

    1. Download the latest trunk from Google Code or wait till April 1st for the official build
    1. Execute the go.bat
    1. Now create a new project and reference the following dll’s from the build folder (this is assuming you are using NUnit)
  • a. Castle.Core
  • b. Castle.DynamicProxy
  • c. Castle.DynamicProxy2
  • d. Castle.MicroKernal
  • e. Castle.Windsor
  • f. NBehave.Spec.Framework
  • g. NBehave.Spec.NUnit
  • h. NUnit.Framework
  • i. Rhino.Mocks
  • j. …The kitchen sink!

As you can see there are a lot of dependencies but for the most part they are everything you would need to have the optimal BDD experience.

At this point I am really jealous of Gem! 🙂

Here is how you would setup a basic specification fixture.

Pseudo DSL:

these specs are concerning this [Type]
    when this [type] is in this [context]
        then [specify] that it [should behave] this way

The first thing is to setup the using aliases.

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

Then use the namespace to define the concerning type:

namespace MathFlash.Core.EquationGenerator_Specs

In the case above the specs in this file are going to be concerning EquationGenerator_Specs.

Now let’s define our first context.

[Context, Concerning("EquationGenerator")]
public class When_initializing_the_EquationGenerator_with_one_and_five : NUnitSpecBase

As you can see we have defined a class decorated with a Context attribute and a Concerning attribute. We have also inherited from the NUnitSpecBase. The name of the class is defining the context that will govern the expected behavior that we will assert on later.

Next we will define our first specification.

[Specification]
public void Should_generate_equations_where_the_left_hand_side_is_greater_than_or_equal_to_the_lower_bound()

So you have defined a context and specified expected behavior. What is so important about the NUnitSpecBase. Well for one it abstracts the use of the automocking container (I will have a post on that in the next couple of days). It also has several new method conventions that have their roots in rSpec.

protected override void Before_each_spec()

This method will be called before_each_spec similar to the SetUpAttribute.

protected override void After_each_spec()

This method will be called after_each_spec similar to the TearDownAttribute.

Last but not least are the NUnit extension methods. You have two options. You can use the standard CamelCase notation or you can use to more readable underscore notation. For example:

equation.LeftHandSide.ShouldBeGreaterThanOrEqualTo(_lowerBound);

or

equation.LeftHandSide.should_be_greater_than_or_equal_to(_lowerBound);

Why did we give you both? Because we just couldn’t decide on which one to use just yet. I am sure in the end we will decide on one but for now you will have both options. If anything it gets you ready for rSpec once IronRuby is baked!

This is only the beginning. We have a lot more planned for future releases and Gallio will open the door for even more exciting possibilities.

For reference here are all the specs.

using System.Collections.Generic;
using MathFlash.Core.Domain;
using NBehave.Spec.NUnit;
using Context = NUnit.Framework.TestFixtureAttribute;
using Specification = NUnit.Framework.TestAttribute;

namespace MathFlash.Core.EquationGenerator_Specs
{
    [Context]
    public class When_initializing_the_EquationGenerator_with_one_and_five : NUnitSpecBase
    {
        private EquationGenerator _generator;
        private int _lowerBound = 1;
        private int _upperBound = 5;

        protected override void Before_each_spec()
        {
            _generator = new EquationGenerator(_lowerBound, _upperBound);
        }

        [Specification]
        public void Should_generate_equations_where_the_left_hand_side_is_greater_than_or_equal_to_the_lower_bound()
        {
            foreach (var equation in _generator.GenerateEquations())
            {
                equation.LeftHandSide.should_be_greater_than_or_equal_to(_lowerBound);
            }
        }

        [Specification]
        public void Should_generate_equations_where_the_left_hand_side_is_less_than_or_equal_to_the_upper_bound()
        {
            foreach (var equation in _generator.GenerateEquations())
            {
                equation.LeftHandSide.should_be_less_than_or_equal_to(_upperBound);
            }
        }

        [Specification]
        public void Should_generate_equations_where_the_right_hand_side_is_greater_than_or_equal_to_the_lower_bound()
        {
            foreach (var equation in _generator.GenerateEquations())
            {
                equation.RightHandSide.should_be_greater_than_or_equal_to(_lowerBound);
            }
        }

        [Specification]
        public void Should_generate_equations_where_the_right_hand_side_is_less_than_or_equal_to_the_upper_bound()
        {
            foreach (var equation in _generator.GenerateEquations())
            {
                equation.RightHandSide.should_be_less_than_or_equal_to(_upperBound);
            }
        }

        [Specification]
        public void Should_generate_twenty_five_equations()
        {
            var equations = _generator.GenerateEquations();

            equations.Count.should_equal(25);
        }
    }
}
LosTechies welcomes Eric Hexter!!!!