Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to share assertions among test classes without inheritance in NUnit?

In MSpec there is a neat feature that allows you share assertions between multiple tests. They're called "behaviors"

Behaviours define reusable specs that encapsulate a particular set of, you guessed it, behaviours; you’re then able to include these specs in any context that exhibits a particular behaviour.

You define them as a class with assertions (It fields)

public class VehicleThatHasBeenStartedBehaviors
{
    protected static IVehicle vehicle;
    It should_have_a_running_engine = () => vehicle.IsEngineRunning.ShouldBeTrue();
    It should_be_idling = () => vehicle.RevCount.ShouldBeBetween(0, 1000);
}

and include them in your test class like

public class when_starting_a_car
{
    Behaves_like<VehicleThatHasBeenStartedBehaviors> a_started_vehicle;
}

How can I accomplish the same with NUnit?

like image 822
ptomasroos Avatar asked Jan 07 '13 08:01

ptomasroos


2 Answers

You can use extension methods to "package" your type-specific assertions:

public static class VehicleAssertions {
    public static void ShouldBeStarted(this IVehicle vehicle) {
        // TODO: change these to NUnit assertions
        vehicle.IsEngineRunning.ShouldBeTrue();
        vehicle.RevCount.ShouldBeBetween(0, 1000);
    }
}

Use it on a test method:

testVehicle.ShouldBeStarted();
like image 93
Jordão Avatar answered Oct 15 '22 14:10

Jordão


Is there a way to share assertions among test classes without inheritance in NUnit?

Considering you just want to share assertions and you're testing for behaviors on interfaces, you could just create something simple:

public interface IBehavior
{
    void Check();
}

public class VehicleThatHasBeenStartedBehaviors : IBehavior
{
    protected IVehicle vehicle;

    public VehicleThatHasBeenStartedBehaviors(IVehicle vehicle)
    {
        this.vehicle = vehicle;
    }

    public void Check()
    {
        Assert.That(vehicle.IsEngineRunning, Is.True);
        Assert.That(vehicle.RevCount, Is.LessThanOrEqualTo(1000));
        Assert.That(vehicle.RevCount, Is.GreaterThanOrEqualTo(0));
    }
}

[TestFixture]
public class when_starting_a_car
{
    protected Car car;

    [SetUp]
    public void SetUp()
    {
        car = new Car();
    }

    [Test]
    public void behaves_like_a_started_vehicle()
    {
        new VehicleThatHasBeenStartedBehaviors(car).Check();
    }
}

BUT, if you want to specifically use MSpec syntax, I think you may have to implement it or find some framework that does it for you.

EDIT

Reading your comments on the question I realized you may be wanting to reuse test methods, and not simply assertions. If that's the case, you could write a customized addin for NUnit. That may sound a little overkill, but it's up to you to decide.

My starting point would be writing a customized SuiteBuilder object:

Purpose

A SuiteBuilder is an addin used to build a test fixture from a type. NUnit itself uses a SuiteBuilder to recognize and build TestFixtures.

Using your own suite builder you could read some behavior classes and compose your fixture.

[NUnitAddin]
public class TestCompositionAddinProvider : IAddin
{
    #region IAddin Members

    public bool Install(IExtensionHost host)
    {
        IExtensionPoint builders = host.GetExtensionPoint("SuiteBuilders");
        if (builders == null)
            return false;
        builders.Install(new TestCompositionSuiteBuilder());
        return true;
    }

    #endregion
}
public class TestCompositionSuiteBuilder : ISuiteBuilder
{
    #region ISuiteBuilder Members

    public bool CanBuildFrom(Type type)
    {
                    //TODO: Create validation logic
        return true;
    }

    public NUnit.Core.Test BuildFrom(Type type)
    {
        if (CanBuildFrom(type))
            return new ComposedSuiteExtension(type);
        return null;
    }

    #endregion
}

public class ComposedSuiteExtension : TestSuite
{
    public ComposedSuiteExtension(Type fixtureType)
        : base(fixtureType)
    {
        //TODO: Create logic to add test methods from various behaviors.
    }
}
like image 29
Marcos Brigante Avatar answered Oct 15 '22 14:10

Marcos Brigante