How do you stub an async method using Visual studio's Fakes framework?

时间:2017-07-12 08:09:15

标签: c# async-await mstest stub microsoft-fakes

The methods I need to stub are called e.g. like this:

List<DocumentInfo> documentInfosToDelete = await _documentInfoRepository.GetListByExternalIdAsync(
    partyLegalEntity, 
    externalId,
    type,
    status);

This works, but generates a compiler warning: 'This async method lacks 'await' operators' etc.

   testService.DocumentInfoRepos.GetListByExternalIdAsyncStringStringDocumentTypeDocumentStatus =
                (async (a, b, c, d) => 
            {
                GetListByExternalIdAsyncCalled = true;
                return new List<DocumentInfo>();
            });

I want to get rid of those warnings, as they would drown out any warnings about actual problems.

Returning new Task(...) hangs. If I understand what I have found on the WWW correctly, Task.Run(...) does something completely different from the await async pattern we are using.

What to do?

2 个答案:

答案 0 :(得分:1)

返回new Task(…)挂起,因为这会创建一个未启动的Task。您可以执行的操作是通过调用Task.FromResult来创建已完成的Task

testService.DocumentInfoRepos.GetListByExternalIdAsyncStringStringDocumentTypeDocumentStatus =
        (a, b, c, d) => 
        {
            GetListByExternalIdAsyncCalled = true;
            return Task.FromResult(new List<DocumentInfo>());
        };

此代码的行为与没有async的{​​{1}}方法相同,但不会产生警告。

答案 1 :(得分:0)

@Klaus提出了一个很好的问题,因为,例如,在测试期间,测试调用异步方法的代码如何表现成功,错误和取消是很好的。任务:

中定义了以下内容
  • 任务Task.CompletedTask:属性,获取已成功完成任务的任务
  • Task Task.FromException(Exception):方法,创建一个已完成且具有指定异常的Task。
  • 任务Task.FromCanceled(CancellationToken):方法,创建由于使用指定的取消令牌取消而完成的任务。
  • Task Task.FromResult(T):方法,获取已成功完成任务的任务
  • Task Task.FromException(Exception):方法,创建一个已完成且具有指定异常的Task。
  • 任务Task.FromCanceled(CancellationToken):方法,创建由于使用指定的取消令牌取消而完成的任务。

这些方法和属性显示如下:

public async Task JoeAsync()
{
    await Task.CompletedTask;
}

public async Task JimAsync()
{
    await Task.FromException(new NullReferenceException("Fake null reference"));
}

// Make sure cancelToken.IsCancellationRequested == true
public async Task JoeAsync(CancellationToken cancellationToken)
{
    await Task.FromCanceled(cancellationToken);
}

public async Task<string> JanAsync()
{
    return await Task.FromResult("Should complete successfully");
}

public async Task<string> JedAsync()
{
    return await Task.FromException<string>(new NullReferenceException("Fake null reference"));
}

// Make sure cancelToken.IsCancellationRequested == true
public async Task<string> JanAsync(CancellationToken cancellationToken)
{
    return await Task.FromCanceled<string>(cancellationToken);
}

测试上述方法的代码如下:

Task task;
var cancellationTokenSource = new CancellationTokenSource();
var cancelToken = cancellationTokenSource.Token;

cancellationTokenSource.Cancel();
task = this.JoeAsync();
Trace.Assert(task.IsCompleted);
Trace.Assert(task.IsCompletedSuccessfully);
task = this.JoeAsync(cancelToken);
Trace.Assert(task.IsCanceled);
Trace.Assert(cancelToken.IsCancellationRequested);
task = this.JimAsync();
Trace.Assert(task.IsFaulted);

Task<string> task2;

task2 = this.JanAsync();
Trace.Assert(task2.IsCompleted);
Trace.Assert(task2.IsCompletedSuccessfully);
task2 = this.JanAsync(cancelToken);
Trace.Assert(task2.IsCanceled);
Trace.Assert(cancelToken.IsCancellationRequested);
task2 = this.JedAsync();
Trace.Assert(task2.IsFaulted);