2013-02-28 40 views
0

我有一個使用MVVM模式的WPF項目。如何在我的WPF MVVM單元測試中避免交叉線程問題?

在特定的視圖模型中,我使用後臺任務(Task類)定期填充ObservableCollection。

我用下面的代碼來實際填充集合:

private void InitialiseAssignablePermissions() 
    { 
     var assignablePermissions = DetermineAssignablePermissions(); 

     CurrentDispatcher.Invoke(() => 
     { 
      foreach (var ap in assignablePermissions) 
      { 
       AssignablePermissions.Add(ap); 
      } 
     }); 
    } 

這工作完全和我的單元測試運轉順暢和所有走向綠色。但是,如果我有一個ICollectionView連接到ObservableCollection,當我運行測試時,我得到一個跨線程異常,並且測試失敗。當我第一次嘗試將項目添加到集合時,會發生異常。儘管項目執行時,代碼仍然愉快地運行。我需要收集視圖,因爲我想過濾項目。

唯一的例外是:

This type of CollectionView does not support changes to its 
SourceCollection from a thread different from the Dispatcher thread. 

的CurrentDispatcher類是一個簡單的我加的單元測試:

internal static class CurrentDispatcher 
{ 
    internal static void Invoke(Action action) 
    { 
     if (App.Current != null) 
      App.Current.Dispatcher.Invoke(action); 
     else 
      action(); 
    } 
} 

我怎樣才能加入集合視圖,仍然單元測試?

+0

你檢查該單位在測試App.Current不等於空?並且您還應該檢查Dispatcher.Thread.IsAlive以防萬一。 – TYY 2013-02-28 18:32:27

回答

0

我在爲我的WPF項目編寫測試時遇到了同樣的問題。問題在於當您在運行測試項目時調用invoke時,調度程序未運行。

您可以通過在單獨的線程上運行調度程序來解決此問題。正如你可能會注意到的,不正確的堆棧跟蹤會在失敗時顯示,所以我調用assert.fail並將堆棧跟蹤追加到錯誤消息中,而不是重新拋出從調度程序接收到的未處理的異常。如果有人知道更好的處理方法,請告訴我。

這裏是我最後使用的代碼:

public static void RunTestInDispatcher(Action action) 
    { 
     failException = null; 
     GetDispatcher().Invoke(action); 

     if (failException != null) 
     { 
      Assert.Fail(string.Format("{0}\n{1}", failException.Message, failException.StackTrace)); 
     } 
    } 

    private static object dispatcherLock = new object(); 
    private static Dispatcher dispatcher = null; 
    public static Dispatcher GetDispatcher() 
    { 
     lock (dispatcherLock) 
     { 
      if (dispatcher == null) 
      { 
       Thread t = new Thread(new ThreadStart(() => 
       { 
        lock (dispatcherLock) 
        { 
         dispatcher = Dispatcher.CurrentDispatcher; 
         dispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(dispatcher_UnhandledException); 
         Monitor.Pulse(dispatcherLock); 
        } 
        Dispatcher.Run(); 
       })); 

       t.SetApartmentState(ApartmentState.STA); 
       t.Start(); 

       Monitor.Wait(dispatcherLock); 
      } 
     } 
     return dispatcher; 

    } 

    static Exception failException = null; 

    static void dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 
    { 
     e.Handled = true; 
     failException = e.Exception; 
    } 
+0

我假設測試然後被包裹在行動委託中?例如RunTestInDispatcher(()=> {/ * Actions and Asserts * /}); - 這是我的嘗試,但我仍然得到錯誤。 – 2013-08-19 10:34:01

相關問題