Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NullReferenceException when calling async method of mocked object

I'm trying to unit test the LoginExecute method of the following ViewModel using MOQ

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

The INavigationService looks like this

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

My test looks like this

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

The problem is that when line

await this.navigationService.TestMethod();

is called the NullReferenceException is being thrown. If the same method is called without "await" it works as expected. It also works ok if the method is being called on normal NavigationService implementation (not a mock of it). Could you please help me understand why the async method call is producing NullReferenceException?

like image 765
czech_u Avatar asked Aug 09 '13 10:08

czech_u


People also ask

What is a nullreferenceexception?

How to handle C# NullReferenceException? Examples How to handle C# NullReferenceException? Examples NullReferenceException is thrown in C# when you try to access a property of method on an object of null reference. Hence the name Null Reference. Simply put, the object is null. The object here could be a string, a class object, or anything.

Why do I get nullreferenceexception when I try to call dog?

In the example above, we try to call the ToString () method, it will throw a NullReferenceException because dog is pointing to null. In the example above, you will get NullReferenceException because Dogs property is null, there is no way to get the data.

How to check for Null Exception before accessing instance members?

The solution is very simple, you have to check for every possible null exception property before accessing instance members. Check the property before accessing instance members. Method 2 - use Null Conditional Operator (?)


2 Answers

Part of the Task-based Asynchronous Pattern is an implicit assumption that the method never returns null.

This means that for all asynchronous methods, you'll need to mock an actual return value. I recommend using Task.FromResult for the "synchronous success" case, TaskCompletionSource for the "synchronous exception" case, and an async lambda with Task.Delay for the "asynchronous success/exception" cases.

like image 149
Stephen Cleary Avatar answered Oct 07 '22 04:10

Stephen Cleary


I had something similar to this; I had a setup with a callback on an async Task, with the code like this:

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

And it threw an obscure NullReferenceException; adding a Returns(Task.CompletedTask) fixed the issue:

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

Got caught by this today, hope that will help someone with a similar issue.

like image 22
garryp Avatar answered Oct 07 '22 04:10

garryp