2013-08-09 16 views
8

Sto cercando di unit test del metodo LoginExecute delle seguenti ViewModel utilizzando MOQNullReferenceException quando si chiama il metodo asincrono dell'oggetto deriso

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) 
    { 
    } 
} 

L'INavigationService assomiglia a questo

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

Il mio test si presenta come questo

[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 
    } 

Il problema è che quando la linea

await this.navigationService.TestMethod(); 

viene chiamato l'eccezione NullReferenceException viene generata. Se lo stesso metodo viene chiamato senza "attendere", funziona come previsto. Funziona anche se il metodo viene chiamato nella normale implementazione di NavigationService (non una simulazione). Potresti per favore aiutarmi a capire perché la chiamata al metodo asincrono sta producendo NullReferenceException?

risposta

8

Parte del modello asincrono basato su attività è un'ipotesi implicita che il metodo non restituisca mai null.

Ciò significa che per tutti i metodi asincroni, è necessario prendere in giro un valore di ritorno effettivo. Si consiglia di utilizzare Task.FromResult per il caso "sincrono successo", TaskCompletionSource per il caso "eccezione sincrona" e un lambda async con Task.Delay per i casi "asincroni successo/eccezione".

2

Avevo qualcosa di simile a questo; Ho avuto una configurazione con una richiamata da una task asincrona, con il codice come questo:

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

Ed è buttato un NullReferenceException oscura; l'aggiunta di una Returns(Task.CompletedTask) risolto il problema:

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

fatta prendere da questa di oggi, la speranza che aiuterà qualcuno con un problema simile.

+0

Questo numero esatto, questa mattina, mi ha tolto i capelli per ore. –

Problemi correlati