0

我有一个使用 MVVM 模式的 WPF 项目。

在特定的视图模型中,我使用后台任务(任务类)定期填充 ObservableCollection。

我使用下面的代码来实际填充集合:

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

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

这完美地工作,我的单元测试运行愉快,一切都变绿了。

但是,如果我有一个连接到 ObservableCollection 的 ICollectionView,当我运行测试时,我会得到一个跨线程异常并且测试失败。当我第一次尝试将项目添加到集合中时会发生异常。尽管在执行项目时,代码仍然可以愉快地运行。我需要集合视图,因为我想过滤项目。

例外是:

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();
    }
}

如何添加集合视图并仍然进行单元测试?

4

1 回答 1

0

在为我的 WPF 项目编写测试时,我遇到了同样的问题。问题是当您在运行测试项目时调用调用时调度程序没有运行。

您可以通过在单独的线程上运行调度程序来解决此问题。您可能会注意到,错误的堆栈跟踪会在失败时显示,因此我不会重新抛出从调度程序接收到的未处理异常,而是调用 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;
    }
于 2013-03-06T06:24:21.430 回答