2013-03-26 5 views
5

Ich bin mir nicht sicher, wo ich anfangen soll, aber lassen Sie mich Ihnen eine kurze Vorstellung davon geben, wo ich bin und was ich erreichen möchte. Ich bin ziemlich neu in Unit Testing auf MVVM und habe Schwierigkeiten beim Testen der Befehle, die ich ausgesetzt habe, indem ich PRISM-Delegat-Befehlseigenschaften verwendete. Mein Delegat Befehle ruft async-Methode, die gewartet werden muss, damit ich das tatsächliche Ergebnis erhalten kann. Unten ist eine Asyc-Methode, die von der Methode aufgerufen wird, die ich testen wollte.So testen Sie ein ViewModel mit der Async-Methode.

async void GetTasksAsync() 
     { 
      this.SimpleTasks.Clear(); 
      Func<IList<ISimpleTask>> taskAction =() => 
       { 
        var result = this.dataService.GetTasks(); 
        if (token.IsCancellationRequested) 
         return null; 
        return result; 
       }; 
      IsBusyTreeView = true; 

      Task<IList<ISimpleTask>> getTasksTask = Task<IList<ISimpleTask>>.Factory.StartNew(taskAction, token); 
      var l = await getTasksTask;   // waits for getTasksTask 


      if (l != null) 
      { 
       foreach (ISimpleTask t in l) 
       { 
        this.SimpleTasks.Add(t); // adds to ViewModel.SimpleTask 
       } 
      } 
     } 

hier ist auch der Befehl in meiner VM, die von der Asynchron-Methode aufruft oben

this.GetTasksCommand = new DelegateCommand(this.GetTasks); 
     void GetTasks() 
     { 
       GetTasksAsync(); 
     } 

und jetzt ist meine Testmethode geht wie

[TestMethod] 
     public void Command_Test_GetTasksCommand() 
     { 
      MyViewModel.GetTaskCommand.Execute(); // this should populate ViewModel.SimpleTask 
      Assert.IsTrue(MyBiewModel.SimpleTask != null) 
     } 

Zeit, was ich bekommen ist, dass mein ViewModel.SimpleTask = null Dies liegt daran, dass nicht auf das Ende der asynchronen Methode gewartet wird. Ich verstehe, dass es einige verwandte Themen zu diesem bereits im Stapelüberlauf gibt, aber ich konnte etwas nicht finden, das mit meinen DelegateCommands in Verbindung steht.

Antwort

9

Ihre Methode GetTasksAsync sollte eine Aufgabe zurückgeben, damit Sie tatsächlich darauf warten können.

Ich empfehle this series auf Channel9 und speziell this episode Ihr Problem zu erklären.

einfach zu machen ist klar: einfach die Unterschrift von GetTasksAsync Wechsel zu

Task GetTasksAsync(); 

ermöglicht es Ihnen, dies zu tun:

var t = GetAsync(); 
t.Wait(); 
Assert(...); 

Falls Sie den Befehl testen wollen wirklich in Ihren Unit-Tests und nicht die tatsächlich vom Befehl aufgerufene Methode, Sie können ein Feld in Ihrem ViewModel verwenden, um die zu wartende Aufgabe zu speichern (nicht so sauber) oder ersetzen Sie Ihren DelegateCommand durch etwas wie in diesem Beitrag beschrieben: Awaitable DelegateCommand

Update: Zusätzlich zu dem Blogbeitrag und der Überlegung, dass Sie PRISM verwenden, sollten Sie einen Project Kona aus dem gleichen Team wie PRISM suchen. Sie implementiert tatsächlich DelegateCommand to support AsyncHandlers

+3

Oder noch besser, dies ermöglicht es Ihnen, eine 'Async-Task'-Unit-Test zu verwenden und erwarten' GetTasksAsync() '. –

+0

Danke für die Antwort. Diese GetTasksAsync() ist jedoch eine private Methode innerhalb meines Viewmodel und möchte keine anderen Objekte in meinem Projekt verfügbar machen und wird nur von Delegierten aufgerufen. Nachdem ich gesagt habe, dass ich nur öffentliche Methoden teste. Diese Delegierten werden öffentlich dargestellt. Die Einführung eines anderen Feldes könnte ein Weg sein, aber Sie haben Recht, es wird schmutzig sein. Ich schaue mir den Link "Angemeldete Delegierte Komma" an, den Sie mir geschickt haben und sehen Sie, ob er nützlich sein wird. –

+0

Update: Ich habe Ihre obige Antwort für die Tatsache, dass ich noch andere Alternative für die Lösung - z. Akzeptierbarer DelegateCommand. Dies bedeutet, dass ich meine privaten Methoden in public geändert habe (das riecht!). Nun ist mein Problem, dass wenn GetTaskAsync() mit t.Wait() aufgerufen wird, drum InnerException = {"Dieser Typ von CollectionView unterstützt keine Änderungen an seinem SourceCollection aus einem Thread, der sich vom Dispatcher-Thread unterscheidet. "}. Dies, weil es Elemente aus dem anderen Thread in meine Sammlung hinzufügt. Irgendeine Idee? –