【问题标题】:NullReferenceException when calling async method of mocked object调用模拟对象的异步方法时出现 NullReferenceException
【发布时间】:2013-08-09 10:27:03
【问题描述】:

我正在尝试使用 MOQ 对以下 ViewModel 的 LoginExecute 方法进行单元测试

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

INavigationService 看起来像这样

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

我的测试是这样的

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

问题是当行

await this.navigationService.TestMethod();

被称为 NullReferenceException 正在被抛出。如果在没有“等待”的情况下调用相同的方法,它会按预期工作。如果在正常 NavigationService 实现上调用该方法(不是模拟它),它也可以正常工作。你能帮我理解为什么异步方法调用会产生 NullReferenceException 吗?

【问题讨论】:

    标签: c# unit-testing asynchronous mocking mstest


    【解决方案1】:

    基于任务的异步模式的一部分是隐含假设该方法永远不会返回null

    这意味着对于所有异步方法,您都需要模拟一个实际的返回值。我建议将Task.FromResult 用于“同步成功”情况,TaskCompletionSource 用于“同步异常”情况,将async lambda 与Task.Delay 用于“异步成功/异常”情况。

    【讨论】:

      【解决方案2】:

      我有类似的东西;我在异步任务上设置了回调,代码如下:

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

      它抛出了一个不起眼的 NullReferenceException;添加Returns(Task.CompletedTask) 解决了这个问题:

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

      今天遇到了这个问题,希望对遇到类似问题的人有所帮助。

      【讨论】:

      • 今天早上这个确切的问题让我把头发拉了好几个小时。
      猜你喜欢
      • 1970-01-01
      • 2015-10-09
      • 2018-07-22
      • 2014-09-28
      • 2020-12-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-18
      • 1970-01-01
      相关资源
      最近更新 更多