原文作者: 周银辉 来源: 博客园 原文地址:http://www.cnblogs.com/zhouyinhui/archive/2007/09/30/911522.html
可能你已发现一个问题,我们无法使用VS对WPF项目创建单元测试(VS2005不行,VS2008我没试过,但据说也不行),这让人很郁闷,这里将介绍如何使用NUnit来对WPF项目创建单元测试并解决其中的难题(但利用NUnit来对WPF创建单元测试时并不会像针对.Net2.0一样容易,可能会出现一些小问题).
1,对普通类(非WPF UI组件)进行测试:
这和在.Net2.0中使用NUnit进行测试时一样,不会出现任何问题,参考下面的代码:

[TestFixture]

public class ClassTest

{

[Test]

public void TestRun()

{

ClassLibrary1.Class1 obj = new ClassLibrary1.Class1();


double expected = 9;

double result = obj.GetSomeValue(3);


Assert.AreEqual(expected, result);

}

}
2,对WPF UI组件进行测试
使用NUnit对WPF UI组件(比如MyWindow,MyUserControl)进行测试的时候,NUnit会报如下异常:“The calling thread must be STA, because many UI components require this”。
下面是错误的测试代码:

[TestFixture]

public class ClassTest

{

[Test]

public void TestRun()

{

WindowsApplication1.Window1 obj = new WindowsApplication1.Window1();


double expected = 9;

double result = obj.GetSomeValue(3);


Assert.AreEqual(expected, result);

}

}

为了让调用线程为STA,我们可以编写一个辅助类CrossThreadTestRunner:

using System;

using System.Collections.Generic;

using System.Text;

using System.Threading;

using System.Security.Permissions;

using System.Reflection;


namespace TestUnit

{

public class CrossThreadTestRunner

{

private Exception lastException;


public void RunInMTA(ThreadStart userDelegate)

{

Run(userDelegate, ApartmentState.MTA);

}


public void RunInSTA(ThreadStart userDelegate)

{

Run(userDelegate, ApartmentState.STA);

}


private void Run(ThreadStart userDelegate, ApartmentState apartmentState)

{

lastException = null;


Thread thread = new Thread(

delegate()

{

try

{

userDelegate.Invoke();

}

catch (Exception e)

{

lastException = e;

}

});

thread.SetApartmentState(apartmentState);


thread.Start();

thread.Join();


if (ExceptionWasThrown())

ThrowExceptionPreservingStack(lastException);

}


private bool ExceptionWasThrown()

{

return lastException != null;

}


[ReflectionPermission(SecurityAction.Demand)]

private static void ThrowExceptionPreservingStack(Exception exception)

{

FieldInfo remoteStackTraceString = typeof(Exception).GetField(

"_remoteStackTraceString",

BindingFlags.Instance | BindingFlags.NonPublic);

remoteStackTraceString.SetValue(exception, exception.StackTrace + Environment.NewLine);

throw exception;

}

}

}
并编写正确的测试代码:

另外,使用NUnit时,您需要添加对nunit.framework.dll的引用,并对测试类添加[TestFixture]属性标记以及对测试方法添加[Test]属性标记,然后将生成的程序集用nunit.exe打开就可以了,关于NUnit的具体用法您可以参考其官方文档