加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何单元测试在MVVM中调用异步方法的DelegateCommand

发布时间:2020-12-15 18:04:30 所属栏目:百科 来源:网络整理
导读:我是新的单元测试MVVM和使用PRISM在我的项目.我正在对我们当前的项目进行单元测试,没有运气在线查找资源,告诉我如何测试调用异步方法的DelegateCommand.这是对我的帖子 – How to Unit Test a ViewModel with async method.的后续问题,关于如何在MVVM中单元
我是新的单元测试MVVM和使用PRISM在我的项目.我正在对我们当前的项目进行单元测试,没有运气在线查找资源,告诉我如何测试调用异步方法的DelegateCommand.这是对我的帖子 – How to Unit Test a ViewModel with async method.的后续问题,关于如何在MVVM中单元测试异步方法,并回答说可以使用异步TestMethod测试公共方法.只有当我想测试的方法是公共方法时,这种情况才会起作用.

问题是我想测试我的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
                }
            }
        }

这里也是我的虚拟机中调用上述异步方法的命令

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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读