0

MVVM パターンを使用した WPF プロジェクトがあります。

特定のビューモデルでは、バックグラウンド タスク (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();
    }
}

コレクション ビューを追加して単体テストを行うにはどうすればよいですか?

4

1 に答える 1

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;
    }
于 2013-03-06T06:24:21.430 に答える