簡體   English   中英

如何單元測試在MVVM中調用異步方法的DelegateCommand

[英]How to Unit Test DelegateCommand that calls async methods in MVVM

我是單元測試MVVM的新手,並在我的項目中使用PRISM。 我正在我們當前的項目上實現單元測試,而沒有運氣在線查找資源,這會告訴我如何調用異步方法的totest DelegateCommand。 這是我的帖子的后續問題 - 如何使用異步方法對ViewModel進行單元測試。 關於如何在MVVM中單元測試異步方法,並回答公共方法可以使用異步TestMethod進行測試。 僅當我要測試的方法是公共方法時,此方案才有效。

問題是我想測試我的DelegateCommand,因為這是我想在其他類上公開的唯一公共細節,其他一切都是私有的。 我可以公開我的私人方法,但我永遠不會這樣做,因為它是一個糟糕的設計。 我不確定如何解決這個問題 - 是否需要對DelegateCommand進行測試,還是有其他一些工作? 我很想知道其他人如何去做,並以某種方式引導我走向正確的道路。

這是我的代碼

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

這里也是我的VM中的命令,它調用上面的異步方法

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

現在我的測試方法就像

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

目前我得到的是我的ViewModel.SimpleTask = null這是因為它不等待異步方法完成。

我編寫了一個AsyncCommand類,它從Execute方法返回一個Task對象。 然后,您需要顯式實現ICommand.Execute ,等待Execute實現中的Task:

public class AsyncCommand : ICommand
{
    public event EventHandler CanExecuteChanged;

    public Func<Task> ExecutedHandler { get; private set; }

    public Func<bool> CanExecuteHandler { get; private set; }

    public AsyncCommand(Func<Task> executedHandler, Func<bool> canExecuteHandler = null)
    {
        if (executedHandler == null)
        {
            throw new ArgumentNullException("executedHandler");
        }

        this.ExecutedHandler = executedHandler;
        this.CanExecuteHandler = canExecuteHandler;
    }

    public Task Execute()
    {
        return this.ExecutedHandler();
    }

    public bool CanExecute()
    {
        return this.CanExecuteHandler == null || this.CanExecuteHandler();
    }

    public void RaiseCanExecuteChanged()
    {
        if (this.CanExecuteChanged != null)
        {
            this.CanExecuteChanged(this, new EventArgs());
        }
    }

    bool ICommand.CanExecute(object parameter)
    {
        return this.CanExecute();
    }

    async void ICommand.Execute(object parameter)
    {
        await this.Execute();
    }
}

然后,您可以將異步任務返回方法傳遞給命令類:

public class ViewModel
{
    public AsyncCommand AsyncCommand { get; private set; }

    public bool Executed { get; private set; }

    public ViewModel()
    {
        Executed = false;
        AsyncCommand = new AsyncCommand(Execute);
    }

    private async Task Execute()
    {
        await(Task.Delay(1000));
        Executed = true;
    }
}

在單元測試中,您只需等待Execute方法:

[TestMethod]
public async Task TestAsyncCommand()
{
    var viewModel = new ViewModel();

    Assert.IsFalse(viewModel.Executed);
    await viewModel.AsyncCommand.Execute();

    Assert.IsTrue(viewModel.Executed);
}

另一方面,UI將調用顯式實現的ICommand.Execute方法,該方法負責等待任務。

(*)與此同時,我注意到如果遵循常見的命名約定,任務返回方法實際上應該命名為ExecuteAsync

由於我無法添加評論,為了完整起見,在PRISM 6中你可以嘗試:

ParsingCommand = new DelegateCommand<string>(async (x) => await StartParsing(x));

在Prism 6中,您可以從異步處理程序創建DelegateCommandDelegateCommand<T>

例如:

startParsingCommand=DelegateCommand .FromAsyncHandler(StartParsingAsync,CanStartParsing) .ObservesProperty(()=> IsParserStarted);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM