2013-02-28 36 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

相关问题