10

在 MSpec 中有一个简洁的功能允许您在多个测试之间共享断言。它们被称为“行为”

行为定义了封装一组特定行为的可重用规范,你猜对了,行为;然后,您可以在任何表现出特定行为的上下文中包含这些规范。

您将它们定义为带有断言(It字段)的类

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);
}

并将它们包含在您的测试类中,例如

public class when_starting_a_car
{
    Behaves_like<VehicleThatHasBeenStartedBehaviors> a_started_vehicle;
}

我怎样才能用 NUnit 完成同样的任务?

4

4 回答 4

4

您可以使用扩展方法来“打包”特定类型的断言:

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);
    }
}

在测试方法上使用它:

testVehicle.ShouldBeStarted();
于 2013-01-10T15:12:40.777 回答
3

有没有办法在测试类之间共享断言而不在 NUnit 中继承?

考虑到您只想共享断言并且正在测试接口上的行为,您可以创建一些简单的东西:

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();
    }
}

但是,如果您想专门使用 MSpec 语法,我认为您可能必须实现它或找到一些为您完成它的框架。

编辑

阅读您对这个问题的评论,我意识到您可能想要重用测试方法,而不仅仅是断言。如果是这种情况,您可以为 NUnit 编写自定义插件。这听起来可能有点矫枉过正,但由您决定。

我的出发点是编写一个定制的SuiteBuilder对象:

目的

SuiteBuilder 是用于从类型构建测试夹具的插件。NUnit 本身使用 SuiteBuilder 来识别和构建 TestFixtures。

使用您自己的套件构建器,您可以阅读一些行为类并组成您的固定装置。

[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.
    }
}
于 2013-01-16T12:45:32.037 回答
1

另一个简单的解决方案是在每个适用测试中调用的 Helper 类中创建静态 Assertion 方法。比如像这样:

public static class VehicleAssert 
{
    public void AssertCorrectlyStarted(IVehicle car) 
    {
         vehicle.IsEngineRunning.ShouldBeTrue();
         vehicle.RevCount.ShouldBeBetween(0, 1000); 
    }
 }   

然后在每个测试夹具中像这样使用它:

[TestFixture]
public class CarTest 
{
     [Test]
     public void TestCarStartsCorrectly() 
     {
         var car = new Car();
         car.Start();
         VehicleAssert.AssertCorrectlyStarted(car);
     }
}
于 2013-01-16T13:15:05.597 回答
1

你可能想看看Mixin的概念。

这是一个 SO答案,描述了如何使用 C# 4.0 完成此任务

于 2013-01-08T12:53:51.453 回答