2013-08-09 10 views
8

Ich versuche, die LoginExecute Methode der folgenden Ansichtsmodell zu Unit-Test MOQ mitNullreferenceexception beim Aufruf asynchroner Methode verspottet Objekt

public class LoginViewModel : ViewModelBase, ILoginViewModel 
{ 
    INavigationService navigationService; 
    IDialogService dialogService; 
    IAdminService adminService; 

    public RelayCommand LoginCommand { get; set; } 

    private string _productID; 

    public string ProductID 
    { 
     get { return _productID; } 
     set 
     { 
      _productID = value; 
      RaisePropertyChanged("ProductID"); 
     } 
    } 

    public LoginViewModel(INavigationService navigationService, IDialogService dialogService, IAdminService adminService) 
    { 
     this.navigationService = navigationService; 
     this.dialogService = dialogService; 
     this.adminService = adminService; 
     InitializeCommands(); 
    } 

    private void InitializeCommands() 
    { 
     LoginCommand = new RelayCommand(() => LoginExecute()); 
    } 

    public async Task LoginExecute() 
    { 
     await this.navigationService.TestMethod(); 
     this.navigationService.Navigate(typeof(ITherapistsViewModel)); 
    } 

    public void Initialize(object parameter) 
    { 
    } 
} 

Die INavigationService wie diese

public interface INavigationService 
{ 
    Frame Frame { get; set; } 
    void Navigate(Type type); 
    void Navigate(Type type, object parameter); 
    Task TestMethod(); 
    void GoBack(); 
} 

sieht Mein Test sieht aus wie Dieses

[TestMethod()] 
    public async Task LoginCommandTest() 
    { 
     var navigationService = new Mock<INavigationService>(); 
     var dialogService = new Mock<IDialogService>(); 
     var adminService = new Mock<IAdminService>(); 
     LoginViewModel loginVM = new LoginViewModel(navigationService.Object, dialogService.Object, adminService.Object); 

     await loginVM.LoginExecute(); 

     //Asserts will be here 
    } 

Das Problem ist, dass wenn Linie

await this.navigationService.TestMethod(); 

heißt die NullReferenceException wird geworfen. Wenn dieselbe Methode ohne "Warten" aufgerufen wird, funktioniert sie wie erwartet. Es funktioniert auch in Ordnung, wenn die Methode bei normaler NavigationService-Implementierung aufgerufen wird (kein Spott davon). Könnten Sie mir bitte helfen zu verstehen, warum der Aufruf der asynchronen Methode NullReferenceException erzeugt?

Antwort

8

Ein Teil des aufgabenbasierten asynchronen Musters ist eine implizite Annahme, dass die Methode niemals null zurückgibt.

Dies bedeutet, dass Sie für alle asynchronen Methoden einen tatsächlichen Rückgabewert vortäuschen müssen. Ich empfehle für den Fall "synchroner Erfolg" Task.FromResult, für den Fall "synchroner Ausnahmefall" TaskCompletionSource und für die Fälle "asynchroner Erfolg/Ausnahme" einen async Lambda mit Task.Delay.

2

Ich hatte etwas Ähnliches; Ich hatte ein Setup mit einem Rückruf auf einer Asynchron-Aufgabe, mit dem Code wie folgt aus:

var navigationService = new Mock<INavigationService>() 
    .Setup(s => s.TestMethod()) 
    .Callback(...); 

Und es warf einen dunklen Nullreferenceexception; Hinzufügen einer Returns(Task.CompletedTask) das Problem behoben:

dieses heute gefangen
var navigationService = new Mock<INavigationService>() 
    .Setup(s => s.TestMethod()) 
    .Returns(Task.CompletedTask) 
    .Callback(...); 

Got, der Hoffnung, dass jemand mit einem ähnlichen Problem helfen.

+0

Dieses genaue Problem, heute Morgen, hielt mich meine Haare für Stunden raus. –

Verwandte Themen