TaskScheduler.FromCurrentSynchronizationContext - comment utiliser WPF répartiteur de thread lorsque les tests unitaires

j'ai du code dans un modèle de vue qui appelle un service à travers une tâche. Quand la tâche sera terminée, il y aura une collecte observable. Le problème est qu'il attend la tâche de finir en utilisant la méthode ContinueWith et en fournissant TaskScheduler.FromCurrentSynchronizationContext as task scheduler, de sorte que L'OC soit mis à jour sur le thread de L'interface utilisateur.

jusqu'à présent si bon, mais quand il s'agit de test à l'unité, il jette une exception disant que "le contexte de synchronisation actuelle peut ne pas être utilisé en tant qu'expert en tâches." Si j'utilise un contexte de synchronisation simulée sur le test de l'unité, alors la collecte observable envoie une erreur parce qu'elle est mise à jour à partir du thread du répartiteur.

Est-il possible de contourner ce problème?

Merci.

18
demandé sur Rayshawn 2011-11-10 14:35:06

3 réponses

Ce n'est pas exactement facile, mais ce n'est pas vraiment dur. Ce que vous devez faire est de lancer un Thread worker qui est configuré comme STA et vous démarrez l'exécution du répartiteur. Une fois que vous avez cet ouvrier assis là, vous pouvez lui envoyer du travail à partir des fils de test de l'unité qui, évidemment, ne sont pas initialisés pour ce genre de travail. Donc, d'abord, voici comment vous démarrez le répartiteur fil dans votre configuration de test:

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

Maintenant, si vous voulez proprement fermer ce thread dans votre test de nettoyage, je vous recommande de le faire, il vous suffit de faire la commande suivante:

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

donc, toutes ces choses d'infrastructure hors du chemin, voici tout ce que vous devez faire dans votre test pour exécuter sur ce thread.

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
    }));
}
17
répondu Drew Marsh 2011-12-09 12:05:05

ajoutez ceci à votre initialisation de test, pour créer un contexte:

SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
14
répondu thumbmunkeys 2013-06-02 10:14:01

Ce qui la rend encore plus simple

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

vous pouvez alors utiliser le code scheduler explicitement (initialisé avec TaskScheduler.FromCurrentSynchronizationContext() en cours d'exécution)

0
répondu Martin 2016-12-05 13:47:32