【问题标题】:How do you stub an async method using Visual studio's Fakes framework?如何使用 Visual Studio 的 Fakes 框架存根异步方法?
【发布时间】:2017-07-12 08:09:15
【问题描述】:

我需要存根的方法被称为例如像这样:

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

这可行,但会生成编译器警告:“此异步方法缺少 'await' 运算符”等。

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

我想去掉那些警告,因为它们会淹没任何关于实际问题的警告。

返回新任务(...)挂起。如果我正确理解我在 WWW 上找到的内容,Task.Run(...) 会做一些与我们使用的 await 异步模式完全不同的事情。

怎么办?

【问题讨论】:

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


    【解决方案1】:

    @Klaus 提出了一个很好的问题,因为例如,在测试期间,测试调用异步方法的代码在成功、错误和取消时的表现非常好。 Task中定义了以下内容:

    • Task Task.CompletedTask:属性,获取已经成功完成任务的Task
    • Task Task.FromException(Exception):方法,创建一个已完成但出现指定异常的Task。
    • Task Task.FromCanceled(CancellationToken):方法,使用指定的取消令牌创建因取消而完成的任务。
    • Task Task.FromResult(T):方法,获取已经成功完成任务的Task
    • Task Task.FromException(Exception):方法,创建一个已完成但出现指定异常的Task。
    • 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);
    

    【讨论】:

      【解决方案2】:

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

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

      此代码的行为与没有awaitasync 方法相同,但不会产生警告。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-27
        • 1970-01-01
        • 2012-08-13
        • 2012-05-04
        • 1970-01-01
        相关资源
        最近更新 更多