为WPF项目创建单元测试

                   为WPF项目创建单元测试
                                      周银辉

可能你已发现一个问题,我们无法使用VS对WPF项目创建单元测试(VS2005不行,VS2008我没试过,但据说也不行),这让人很郁闷,这里将介绍如何使用NUnit来对WPF项目创建单元测试并解决其中的难题(但利用NUnit来对WPF创建单元测试时并不会像针对.Net2.0一样容易,可能会出现一些小问题).

1,对普通类(非WPF UI组件)进行测试:
 这和在.Net2.0中使用NUnit进行测试时一样,不会出现任何问题,参考下面的代码:
为WPF项目创建单元测试    [TestFixture]
为WPF项目创建单元测试    
public class ClassTest
为WPF项目创建单元测试为WPF项目创建单元测试    
为WPF项目创建单元测试{
为WPF项目创建单元测试        [Test]
为WPF项目创建单元测试        
public void TestRun()
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            ClassLibrary1.Class1 obj 
= new ClassLibrary1.Class1();
为WPF项目创建单元测试
为WPF项目创建单元测试            
double expected = 9;
为WPF项目创建单元测试            
double result = obj.GetSomeValue(3);
为WPF项目创建单元测试
为WPF项目创建单元测试            Assert.AreEqual(expected, result);
为WPF项目创建单元测试        }

为WPF项目创建单元测试     }

为WPF项目创建单元测试

2,对WPF UI组件进行测试
 使用NUnit对WPF UI组件(比如MyWindow,MyUserControl)进行测试的时候,NUnit会报如下异常:“The calling thread must be STA, because many UI components require this”。
下面是错误的测试代码:
为WPF项目创建单元测试[TestFixture]
为WPF项目创建单元测试    
public class ClassTest
为WPF项目创建单元测试为WPF项目创建单元测试    
为WPF项目创建单元测试{
为WPF项目创建单元测试        [Test]
为WPF项目创建单元测试        
public void TestRun()
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            WindowsApplication1.Window1 obj 
= new WindowsApplication1.Window1();
为WPF项目创建单元测试
为WPF项目创建单元测试            
double expected = 9;
为WPF项目创建单元测试            
double result = obj.GetSomeValue(3);
为WPF项目创建单元测试
为WPF项目创建单元测试            Assert.AreEqual(expected, result);
为WPF项目创建单元测试        }

为WPF项目创建单元测试     }

为WPF项目创建单元测试
为WPF项目创建单元测试


为了让调用线程为STA,我们可以编写一个辅助类CrossThreadTestRunner:
为WPF项目创建单元测试using System;
为WPF项目创建单元测试
using System.Collections.Generic;
为WPF项目创建单元测试
using System.Text;
为WPF项目创建单元测试
using System.Threading;
为WPF项目创建单元测试
using System.Security.Permissions;
为WPF项目创建单元测试
using System.Reflection;
为WPF项目创建单元测试
为WPF项目创建单元测试
namespace TestUnit
为WPF项目创建单元测试为WPF项目创建单元测试
为WPF项目创建单元测试{
为WPF项目创建单元测试    
public class CrossThreadTestRunner
为WPF项目创建单元测试为WPF项目创建单元测试    
为WPF项目创建单元测试{
为WPF项目创建单元测试        
private Exception lastException;
为WPF项目创建单元测试
为WPF项目创建单元测试        
public void RunInMTA(ThreadStart userDelegate)
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            Run(userDelegate, ApartmentState.MTA);
为WPF项目创建单元测试        }

为WPF项目创建单元测试
为WPF项目创建单元测试        
public void RunInSTA(ThreadStart userDelegate)
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            Run(userDelegate, ApartmentState.STA);
为WPF项目创建单元测试        }

为WPF项目创建单元测试
为WPF项目创建单元测试        
private void Run(ThreadStart userDelegate, ApartmentState apartmentState)
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            lastException 
= null;
为WPF项目创建单元测试
为WPF项目创建单元测试            Thread thread 
= new Thread(
为WPF项目创建单元测试              
delegate()
为WPF项目创建单元测试为WPF项目创建单元测试              
为WPF项目创建单元测试{
为WPF项目创建单元测试                  
try
为WPF项目创建单元测试为WPF项目创建单元测试                  
为WPF项目创建单元测试{
为WPF项目创建单元测试                      userDelegate.Invoke();
为WPF项目创建单元测试                  }

为WPF项目创建单元测试                  
catch (Exception e)
为WPF项目创建单元测试为WPF项目创建单元测试                  
为WPF项目创建单元测试{
为WPF项目创建单元测试                      lastException 
= e;
为WPF项目创建单元测试                  }

为WPF项目创建单元测试              }
);
为WPF项目创建单元测试            thread.SetApartmentState(apartmentState);
为WPF项目创建单元测试
为WPF项目创建单元测试            thread.Start();
为WPF项目创建单元测试            thread.Join();
为WPF项目创建单元测试
为WPF项目创建单元测试            
if (ExceptionWasThrown())
为WPF项目创建单元测试                ThrowExceptionPreservingStack(lastException);
为WPF项目创建单元测试        }

为WPF项目创建单元测试
为WPF项目创建单元测试        
private bool ExceptionWasThrown()
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            
return lastException != null;
为WPF项目创建单元测试        }

为WPF项目创建单元测试
为WPF项目创建单元测试        [ReflectionPermission(SecurityAction.Demand)]
为WPF项目创建单元测试        
private static void ThrowExceptionPreservingStack(Exception exception)
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            FieldInfo remoteStackTraceString 
= typeof(Exception).GetField(
为WPF项目创建单元测试              
"_remoteStackTraceString",
为WPF项目创建单元测试              BindingFlags.Instance 
| BindingFlags.NonPublic);
为WPF项目创建单元测试            remoteStackTraceString.SetValue(exception, exception.StackTrace 
+ Environment.NewLine);
为WPF项目创建单元测试            
throw exception;
为WPF项目创建单元测试        }

为WPF项目创建单元测试    }

为WPF项目创建单元测试}

为WPF项目创建单元测试
并编写正确的测试代码:
为WPF项目创建单元测试    [TestFixture]
为WPF项目创建单元测试    
public class ClassTest
为WPF项目创建单元测试为WPF项目创建单元测试    
为WPF项目创建单元测试{
为WPF项目创建单元测试        [Test]
为WPF项目创建单元测试        
public void TestRun()
为WPF项目创建单元测试为WPF项目创建单元测试        
为WPF项目创建单元测试{
为WPF项目创建单元测试            
为WPF项目创建单元测试            CrossThreadTestRunner runner 
= new CrossThreadTestRunner();
为WPF项目创建单元测试            runner.RunInSTA(
为WPF项目创建单元测试              
delegate
为WPF项目创建单元测试为WPF项目创建单元测试              
为WPF项目创建单元测试{
为WPF项目创建单元测试                  Console.WriteLine(Thread.CurrentThread.GetApartmentState());
为WPF项目创建单元测试
为WPF项目创建单元测试                  WindowsApplication1.Window1 obj 
= new WindowsApplication1.Window1();
为WPF项目创建单元测试
为WPF项目创建单元测试                  
double expected = 9;
为WPF项目创建单元测试                  
double result = obj.GetSomeValue(3);
为WPF项目创建单元测试                  Assert.AreEqual(expected, result);
为WPF项目创建单元测试              }
);   
为WPF项目创建单元测试
为WPF项目创建单元测试        }

为WPF项目创建单元测试  }

为WPF项目创建单元测试
为WPF项目创建单元测试
为WPF项目创建单元测试
为WPF项目创建单元测试

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

DEMO           NUnit

转载于:https://www.cnblogs.com/zhouyinhui/archive/2007/09/30/911522.html