这是我第一次编写异步方法的单元测试。我正在使用 xUnit 。我搜索了 SO ,没有令人反感的结果。我发现,但对我没有用的最好方法是实现THIS示例中的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:对象引用未设置为 对象的实例。
提前感谢您的时间和建议。
答案 0 :(得分:2)
problems of async void
methods之一是它们很难测试。对于您的问题,大多数开发人员执行以下操作之一:
IAsyncCommand
界面。async Task
并公开。有关详细信息,请参见我的MSDN magazine article on the subject。
这是第二种方法的示例:
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依赖性,那么define your own IAsyncCommand
and AsyncCommand
types并不难。