zz from http://www.cnblogs.com/zhouyinhui/archive/2007/09/30/911522.html
为WPF项目创建单元测试 周银辉 可能你已发现一个问题,我们无法使用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; } } }
并编写
正确的 测试代码:
[TestFixture]
public
class
ClassTest
{ [Test] public void TestRun() { CrossThreadTestRunner runner = new CrossThreadTestRunner(); runner.RunInSTA( delegate { Console.WriteLine(Thread.CurrentThread.GetApartmentState()); WindowsApplication1.Window1 obj = new WindowsApplication1.Window1(); double expected = 9 ; double result = obj.GetSomeValue( 3 ); Assert.AreEqual(expected, result); } ); } }
另外,使用NUnit时,您需要添加对nunit.framework.dll的引用,并对测试类添加[TestFixture]属性标记以及对测试方法添加[Test]属性标记,然后将生成的程序集用nunit.exe打开就可以了,关于NUnit的具体用法您可以参考其官方文档
DEMO
NUnit