2012-02-17 15 views
5

Sto cercando di seguire al fine di ottenere il mio test NUnit per eseguire i suggerimenti da Using the WPF Dispatcher in unit tests.metodo corretto per utilizzare il WPF Dispatcher in unità di test

Quando scrivo il mio test di unità come sotto, funziona:

[Test] 
public void Data_Should_Contain_Items() 
{ 
    DispatcherFrame frame = new DispatcherFrame(); 
     PropertyChangedEventHandler waitForModelHandler = delegate(object sender, PropertyChangedEventArgs e) 
     { 
      if (e.PropertyName == "Data") 
      { 
      frame.Continue = false; 
      } 
     }; 
    _myViewModel.PropertyChanged += waitForModelHandler; 
    Dispatcher.PushFrame(frame); 

    Assert.IsTrue(_myViewModel.Data.Count > 0, "Data item counts do not match"); 
} 

Tuttavia, se si tenta di utilizzare il suggerimento del DispatcherUtil, non funziona:

[Test] 
public void Data_Should_Contain_Items() 
{ 
    DispatcherUtil.DoEvents(); 
    Assert.IsTrue(_myViewModel.Data.Count > 0, "Data item counts do not match"); 
} 

public static class DispatcherUtil 
{ 
    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
    public static void DoEvents() 
    { 
     DispatcherFrame frame = new DispatcherFrame(); 
     Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
      new DispatcherOperationCallback(ExitFrame), frame); 
     Dispatcher.PushFrame(frame); 
    } 

    private static object ExitFrame(object frame) 
    { 
     ((DispatcherFrame)frame).Continue = false; 
     return null; 
    } 
} 

Quando ho sto usando DispatcherUtil, sembra che la chiamata a ExitFrame si verifichi troppo presto, prima che i dati siano pronti.

Non sono io usando correttamente la DispatcherUtil? Sembra un metodo migliore da utilizzare per gestire il dispatcher piuttosto che attendere i callback dal modello di visualizzazione.

+0

Cosa stai cercando di provare, solo se il PropertyChangedEventHandler viene invocato per la proprietà "dati"? In tal caso, perché è necessario coinvolgere il dispatcher? Inoltre, non utilizzo _myViewModel per collegare il gestore. – Phil

+0

@Phil: quando _myViewModel viene istanziato, il suo costruttore effettua una chiamata asyn. Al termine della chiamata, _myViewModel.Data dovrebbe avere alcuni valori. Sto provando a verificare che Data sia effettivamente popolato, ma il fatto che Data sia popolata come risultato di una chiamata asyn è ciò che mi sta causando dei problemi. Vorrei evitare di dover ascoltare gli eventi di PropertyChanged in qualsiasi unit test che potrebbe avere a che fare con il Dispatcher. – Flack

risposta

7

Dal momento che il dispatcher è problematico in unit test, la mia soluzione sarebbe quella di rompere la dipendenza vostra propria visione-modello sul dispatcher. Presumo che i riferimenti attualmente avete hard coded come:

Dispatcher.CurrentDispatcher.BeginInvoke(.. 

Il dispatcher è una dipendenza esterna e non dovrebbe essere una parte del tuo test di unità - siamo in grado di assumere i lavori dispatcher.

vorrei utilizzare l'iniezione di dipendenza (sia Mans poveri, Unità, ecc). Creare un'interfaccia adatta che rappresenti il ​​dispatcher. Creare un'implementazione reale che avvolge il dispatcher reale. Creare un'implementazione fittizia che utilizza Action.BeginInvoke. Nel falso si registrano tutti gli IAsyncResults restituiti alle chiamate a BeginInvoke.
Quindi disporre di un metodo di supporto che attenda il completamento di tutte le chiamate che è possibile utilizzare nel test per attendere il completamento.

o avere una classe base vista del modello che fa la stessa cosa. Chiama normalmente il dispatcher ma può essere diretto a chiamare un falso durante i test.

0

Ho trovato una soluzione facile. Invece di elaborare i Frames Async nel Dispatcher, ho aggiunto un altro metodo sincronizzato alla classe DispatcherUtil. La chiamata a questo DoEventsSync() - metodo restituisce quando tutti i fotogrammi sono stati elaborati, credo che questo dovrebbe aiutare qui:

public static class DispatcherUtil 
    { 
     [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
     public static void DoEvents() 
     { 
      var frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, 
       new DispatcherOperationCallback(ExitFrame), frame); 
      Dispatcher.PushFrame(frame); 
     } 

     public static void DoEventsSync() 
     { 
      var frame = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, 
       new DispatcherOperationCallback(ExitFrame), frame); 
      Dispatcher.PushFrame(frame); 
     } 

     private static object ExitFrame(object frame) 
     { 
      ((DispatcherFrame)frame).Continue = false; 
      return null; 
     } 
    } 
Problemi correlati