zoukankan      html  css  js  c++  java
  • 单元测试框架NUnit 之 Extensibility 例子

    首先定义一个自定义的attribute

    using System;
    
    namespace NUnit.Core.Extensions
    {
    	/// <summary>
    	/// 这个自定义特性只是用来标记类,Nunit发现这个标记的类会调用我们插件的逻辑来构建测试类
    	/// </summary>
    	[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
    	public sealed class SampleFixtureExtensionAttribute : Attribute
    	{
    	}
    }

    下面是一个插件的主要逻辑:

    using System;
    using NUnit.Core.Builders;
    using NUnit.Core.Extensibility;
    
    namespace NUnit.Core.Extensions
    {
            //  此处应用NUnitAddin特性
    	[NUnitAddin(Description="这个插件的就是包装了NUnitTestFixture,对SetUp 和 TearDown 的逻辑进行改变。 ")]
    	public class SampleFixtureExtensionBuilder : ISuiteBuilder, IAddin
    	{	
    		#region ISuiteBuilder Members
    		public bool CanBuildFrom(Type type)
    		{
    			return Reflect.HasAttribute( type, "NUnit.Core.Extensions.SampleFixtureExtensionAttribute", false );
    		}
    
    		public Test BuildFrom(Type type)
    		{
                if (CanBuildFrom(type))
                {
                    return new SampleFixtureExtension(type);
                }
    			return null;
    		}
    		#endregion
    
    		#region IAddin Members
    		public bool Install(IExtensionHost host)
    		{
    			IExtensionPoint suiteBuilders = host.GetExtensionPoint( "SuiteBuilders" );
    			if ( suiteBuilders == null )
    				return false;
    
    			suiteBuilders.Install( this );
    			return true;
    		}
    		#endregion
    	}
    }

    我们可以看到这个插件实现了ISuiteBuilder接口,是对SuiteBuilder扩展点进行的扩展,扩展点的主要作用就是从类构建测试类的。当Nunit启动时,会扫描addins目录,加载所有程序集,扫描其中的所有公共类,如果实现了NUnitAddin,就会把该类型存储进一个数组中。而当core初始化时,会先加载扩展点和内建的扩展,然后遍历之前的数组,构造这个类的实例,对我们的例子就是SampleFixtureExtensionBuilder 类,转型为IAddIn调用Install并把当前host做为参数传入。如上文所述,被扩展的host实现了IExtensionHost接口,我们的install方法内部就用它的GetExtensionPoint方法获取扩展点对象,此例中获取SuiteBuilders,获取扩展点,它们实现了IExtensionPoint或IExtensionPoint2接口,调用扩展点对象的Install方法,把扩展本身传入。所有扩展点的Install方法都是继承自ExtensionPoint的,因此所有的扩展点的install方法逻辑都是一样的,只不过此处采用的模板模式,会调用各个扩展点类的检查,是不是合适的扩展,然后加入了扩展集合。

    这些还是不够的,我们想把以自定义特性SampleFixtureExtensionAttribute 的类构建成什么样的测试类呢?

    using System;
    
    namespace NUnit.Core.Extensions
    {
    	/// <summary>
    	/// 此类继承自NUnitTestFixture,对可以扩展的方法进行重写
    	/// </summary>
    	class SampleFixtureExtension : NUnitTestFixture
    	{
    		public SampleFixtureExtension( Type fixtureType ) 
    			: base( fixtureType )
    		{
                            //  这里不需要做什么,因为我们使用了基类的构造
    
    		}
                    // 下面是我们重写了基类的方法
    		protected override void DoOneTimeSetUp(TestResult suiteResult)
    		{
    			Console.WriteLine( "Extended Fixture SetUp called" );
    			base.DoOneTimeSetUp (suiteResult);
    		}
    
    		protected override void DoOneTimeTearDown(TestResult suiteResult)
    		{
    			base.DoOneTimeTearDown (suiteResult);
    			Console.WriteLine( "Extended Fixture TearDown called" );
    		}
    	}
    }

    好,扩展大功告成,再来看我们扩展里的ISuiteBuilder 成员中的BuildFrom方法,它会把符合条件的类构建成SampleFixtureExtension 类型的类,至于是怎么构建的,这个我们调用了基类NUnitTestFixture的构造方法。

    下面建一个测试项目引用我们的插件项目生成的dll,新建一个测试类,来测试下我们的插件。

    using System;
    using NUnit.Framework;
    using NUnit.Core.Extensions;
    
    namespace NUnit.Extensions.Tests
    {
    	/// <summary>
    	/// Test class that demonstrates SampleFixtureExtension
    	/// </summary>
    	[SampleFixtureExtension]
    	public class SampleFixtureExtensionTests
    	{
    		[TestFixtureSetUp]
    		public void SetUpTests()
    		{
    			Console.WriteLine( "TestFixtureSetUp called" );
    		}
    
    		[TestFixtureTearDown]
    		public void FixtureTearDown()
    		{
    			Console.WriteLine( "TestFixtureTearDown called" );
    		}
    
    		[Test]
    		public void SomeTest()
    		{
                Assert.IsEmpty("");
    		}
    
    		[Test]
    		public void AnotherTest()
    		{
                Assert.IsNaN(5d);
    		}
    	}
    }

    编译测试项目。

    把编译好的插件的dll复制一份到nunit安装目录的addins目录下,运行nunit.exe,这时点击Tools菜单的addin,我们可以看到插件列表,这里可以看到我们的插件。然后添加你的测试项目进来,run。在输出的Text output选项卡中,可以看到:

    Extended Fixture SetUp called
    TestFixtureSetUp called
    TestFixtureTearDown called
    Extended Fixture TearDown called

    可知,我们插件已经正常工作了,我们新加了nunit本身所没有的行为,插件的目的也就达到了。

    但是,为什么我们测试类另两个普通的测试方法没有运行呢?你可以看一下nunit界面测试树上,根本就没有这两个方法的结点?我们知道我们构建的测试类继承自NUnitTestFixture的,这个类的构造函数只会处理其中标记为setup和teardown方法,因此其它两个普通的方法根本没被构建,因此测试的树上就没有这两个方法的结点,更不要说运行了。

    如果

    如果我们把测试类上的SampleFixtureExtension标记移除掉,结果如何呢?

    移除之后重新编译,再来看界面的测试树,SomeTest和AnotherTest的结点已经出现了:由此我们可以知道nunit监视测试项目的dll,当它改变时,就会构建测试。此时这个测试类只是一个变通的测试类,这两个方法也被构建了。Run,结果??

    有一个错误,在Errors or failures选项卡上,我们得到这样的信息:

    NUnit.Extensions.Tests.SampleFixtureExtensionTests.AnotherTest:
      Expected: NaN
      But was:  5.0d

    这个断言失败了,正是我们想的结果。

    在Text output选项卡,有这样的信息:

    TestFixtureSetUp called
    ***** NUnit.Extensions.Tests.SampleFixtureExtensionTests.SomeTest
    TestFixtureTearDown called

    这就是最简单的测试行为了。

    《完》

  • 相关阅读:
    信号的阻塞
    善用布尔值
    多线程
    手机号码合理性的判断
    P(n,x)实现
    兄弟分钱、海盗分赃
    简单四则运算的实现
    模板技术
    合并字符串
    交换机和路由器比较
  • 原文地址:https://www.cnblogs.com/forcertain/p/2257290.html
Copyright © 2011-2022 走看看