【问题标题】:Is there a way to share assertions among test classes without inheritance in NUnit?有没有办法在测试类之间共享断言而不在 NUnit 中继承?
【发布时间】:2013-01-07 08:33:54
【问题描述】:

在 MSpec 中有一个简洁的功能,允许您在多个测试之间共享断言。他们叫"behaviors"

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

您将它们定义为带有断言的类(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 完成同样的任务?

【问题讨论】:

标签: .net unit-testing nunit mspec


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    有没有办法在测试类之间共享断言而无需 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 语法,我认为您可能必须实现它或找到一些框架来为您完成它。

    编辑

    阅读您的 cmets 后,我意识到您可能想要重用测试方法,而不仅仅是断言。如果是这种情况,您可以写一个customized addin for 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.
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可能想看看Mixin 的概念。

      这是一个 SO answer 描述如何使用 C# 4.0 完成此操作

      【讨论】:

      • 但是,我认为这种方法不适用于开箱即用的 NUnit 测试运行器。它使用基本反射来查找用其特定属性修饰的类/方法。这是动态查找?
      【解决方案4】:

      另一个简单的解决方案是在您在每个适用测试中调用的 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);
           }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多