为WPF项目创建单元测试
 
2008-12-18 来源:网络
 

可能你已发现一个问题,我们无法使用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的具体用法您可以参考其官方文档 。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织