单元测试框架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

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

 

《完》

posted @ 2011-11-21 15:43  for certain  阅读(517)  评论(2编辑  收藏  举报