为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的具体用法您可以参考其官方文档。

你可能感兴趣的:(thread,exception,单元测试,测试,Class,WPF)