為WPF項目創建單元測試

作者: 周銀輝  來源: 博客園  發布時間: 2009-02-27 15:08  閱讀: 4761 次  推薦: 0   原文鏈接   [收藏]  

可能你已發現一個問題,我們無法使用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);
        }

     }

wpfUnitTestError1.png


為了讓調用線程為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);
              }
);   

        }

  }



wpfUnitTestOK.png

另外,使用NUnit時,您需要添加對nunit.framework.dll的引用,并對測試類添加[TestFixture]屬性標記以及對測試方法添加[Test]屬性標記,然后將生成的程序集用nunit.exe打開就可以了,關于NUnit的具體用法您可以參考其官方文檔。

0
0
 
標簽:WPF
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()