繁体   English   中英

如何使用xUnit测试包含await的异步void DelegateCommand方法?

[英]How to test async void DelegateCommand method containing await with xUnit?

这是我第一次编写异步方法的单元测试。 我正在使用xUnit 我搜索了SO ,但没有令人惊讶的结果。 最好的,我发现了,但对我没有工作,是贯彻落实IAsyncLifetime例子。 如果有任何提示可以解决此问题,我将不胜感激。

目前我所拥有的。 在经过测试的VM中,我有一个命令:

public ICommand TestResultsCommand { get; private set; }

然后在VM构造函数中初始化命令,如下所示:

TestResultsCommand = new DelegateCommand(OnTestResultExecuteAsync);

命令调用方法:

private async void OnTestResultExecuteAsync(object obj)
        {
            TokenSource = new CancellationTokenSource();
            CancellationToken = TokenSource.Token;

            await TestHistoricalResultsAsync();
        }

TestHistoricalResultsAsync方法的签名如下:

private async Task TestHistoricalResultsAsync()

现在,进入单元测试项目。 目前在测试课中,我有一个方法:

[Fact]//testing async void
        public void OnTestResultExecuteAsync_ShouldCreateCancellationTokenSource_True()
        {
            CancellationTokenSource tokenSource = new CancellationTokenSource();
            CancellationToken cancellationToken = tokenSource.Token;
            _viewModel.TestResultsCommand.Execute(null);
            Assert.Equal(cancellationToken.CanBeCanceled, _viewModel.CancellationToken.CanBeCanceled);
            Assert.Equal(cancellationToken.IsCancellationRequested, _viewModel.CancellationToken.IsCancellationRequested);
        }

测试给我一个例外:

消息:System.NullReferenceException:对象引用未设置为对象的实例。

异常的堆栈跟踪为: 在此处输入图片说明

预先感谢您的时间和建议。

async void方法问题之一是它们很难测试。 对于您的问题,大多数开发人员执行以下操作之一:

  1. 定义并使用IAsyncCommand接口。
  2. 使他们的逻辑async Task和公开。
  3. 使用支持异步命令的框架,例如MvvmCross。

有关详细信息,请参阅我的MSDN杂志文章

这是第二种方法的示例:

TestResultsCommand = new DelegateCommand(async () => await OnTestResultExecuteAsync());

public async Task OnTestResultExecuteAsync()
{
  TokenSource = new CancellationTokenSource();
  CancellationToken = TokenSource.Token;

  await TestHistoricalResultsAsync();
}

[Fact]
public async Task OnTestResultExecuteAsync_ShouldCreateCancellationTokenSource_True()
{
  CancellationTokenSource tokenSource = new CancellationTokenSource();
  CancellationToken cancellationToken = tokenSource.Token;
  await _viewModel.OnTestResultExecuteAsync();
  Assert.Equal(cancellationToken.CanBeCanceled, _viewModel.CancellationToken.CanBeCanceled);
  Assert.Equal(cancellationToken.IsCancellationRequested, _viewModel.CancellationToken.IsCancellationRequested);
}

如果您不想仅仅为了进行单元测试而公开async Task方法,则可以使用某种类型的IAsyncCommand 或者是您自己的(如我的文章中所述)或库中的一个(例如,MvvmCross)。 这是使用MvvmCross类型的示例:

public IMvxAsyncCommand TestResultsCommand { get; private set; }

TestResultsCommand = new MvxAsyncCommand(OnTestResultExecuteAsync);

private async Task OnTestResultExecuteAsync() // back to private
{
  TokenSource = new CancellationTokenSource();
  CancellationToken = TokenSource.Token;

  await TestHistoricalResultsAsync();
}

[Fact]
public async Task OnTestResultExecuteAsync_ShouldCreateCancellationTokenSource_True()
{
  CancellationTokenSource tokenSource = new CancellationTokenSource();
  CancellationToken cancellationToken = tokenSource.Token;
  await _viewModel.TestResultsCommand.ExecuteAsync();
  Assert.Equal(cancellationToken.CanBeCanceled, _viewModel.CancellationToken.CanBeCanceled);
  Assert.Equal(cancellationToken.IsCancellationRequested, _viewModel.CancellationToken.IsCancellationRequested);
}

如果您喜欢IMvxAsyncCommand方法,但又不想使用MvvmCross依赖性,那么定义自己的IAsyncCommandAsyncCommand类型就AsyncCommand

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM