wpf unit-testing task-parallel-library

TaskScheduler.FromCurrentSynchronizationContext: cómo utilizar el subproceso de WPF dispatcher cuando se realizan pruebas unitarias



unit-testing task-parallel-library (3)

Agregue esto a su inicialización de prueba, para crear un contexto:

SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

Tengo un código en un ViewModel que llama a un servicio a través de una tarea. Cuando la tarea finalice, se rellenará una colección Observable. El problema es que está esperando que la tarea termine utilizando el método ContinueWith y proporcionando TaskScheduler.FromCurrentSynchronizationContext como programador de tareas, para que el OC se actualice en el subproceso de la interfaz de usuario.

Hasta ahora todo bien, pero cuando se trata de pruebas unitarias, lanza una excepción que dice que "el SynchronizationContext actual no se puede usar como un Programador de tareas". Si utilizo un SynchronizationContext simulado en la prueba de la unidad, entonces ObservableCollection arroja un error porque se está actualizando en función del subproceso del distribuidor.

¿Hay alguna manera de evitar esto?

Gracias.


Esto lo hace aún más simple.

TaskScheduler scheduler = Dispatcher.CurrentDispatcher.Invoke(TaskScheduler.FromCurrentSynchronizationContext)

luego, el código puede usar el scheduler explícitamente (inicializado con TaskScheduler.FromCurrentSynchronizationContext() durante el tiempo de ejecución)


No es exactamente fácil, pero tampoco es tan difícil. Lo que debe hacer es girar un subproceso de trabajo que esté configurado como STA y usted inicie el tiempo de ejecución de Dispatcher en él. Una vez que tenga a ese trabajador sentado allí, puede enviar trabajo desde los subprocesos de prueba de la unidad que, obviamente, no están inicializados para este tipo de trabajo. Entonces, primero, así es como inicia el subproceso de despachador en su configuración de prueba:

this.dispatcherThread = new Thread(() => { // This is here just to force the dispatcher infrastructure to be setup on this thread Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { Trace.WriteLine("Dispatcher worker thread started."); })); // Run the dispatcher so it starts processing the message loop Dispatcher.Run(); }); this.dispatcherThread.SetApartmentState(ApartmentState.STA); this.dispatcherThread.IsBackground = true; this.dispatcherThread.Start();

Ahora, si desea cerrar de manera limpia ese hilo en su limpieza de prueba, lo cual le recomiendo que haga, simplemente haga lo siguiente:

Dispatcher.FromThread(this.dispatcherThread).InvokeShutdown();

Por lo tanto, toda esa infraestructura está fuera del camino, aquí está todo lo que necesita hacer en su prueba para ejecutar ese hilo.

public void MyTestMethod { // Kick the test off on the dispatcher worker thread synchronously which will block until the work is competed Dispatcher.FromThread(this.dispatcherThread).Invoke(new Action(() => { // FromCurrentSynchronizationContext will now resolve to the dispatcher thread here })); }