【问题标题】:Stubbing Task returning method in async unit test异步单元测试中的存根任务返回方法
【发布时间】:2012-12-09 03:23:03
【问题描述】:

假设我有以下类和它所依赖的接口:

public class MyController
{
    private IRepository _repository;
    public MyController(IRepository repository)
    {
        _repository = repository;
    }

    public async Task MethodUnderTest(int someId)
    {
        var o = await _repository.FindById(someId);
        // update o
        await _repository.Commit();
    }
}

public interface IRepository
{
    Task Commit();
}

当我对该方法进行单元测试时,我可以执行以下操作(使用 xUnit 和 Rhino Mocks):

[Fact]
public async Task MyTest()
{
    IRepository repositoryStub = MockRepository.GenerateStub<IRepository>();

    MyController controller = new MyController(repositoryStub);

    await controller.MethodUnderTest(1);
}

这会失败并出现 System.NullReferenceException : Object reference not set to an instance of an object

使用以下 StackTrace:

UnitTest.MyController.<MethodUnderTest>d__0.MoveNext() in 
\UnitTest\Class1.cs:line 35
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at \UnitTest\Class1.cs:line 20

由于Commit() 返回null 并且为async/await 生成的状态机在null 上调用MoveNext() 而发生此错误是否正确?

我可以通过以下方式解决此问题:

repositoryStub.Expect(r => r.Commit()).Return(Task.FromResult<bool>(true);

但这感觉有点奇怪..我可以使用任何T 来代替FromResult&lt;T&gt; 并且测试将运行。我找不到将返回非泛型 TaskFromResult 方法。

T 使用什么重要吗?还是我应该以其他方式解决这个问题?

【问题讨论】:

  • 无论您使用什么类型的T,因为Task&lt;T&gt; 扩展了Task。您可以改用Task.Delay(0)。如果您不关心任务本身,您可以将MethodUnderTest 更改为直接返回_repository.Commit(),而不是创建异步方法。
  • Repository.Commit() 使用 Entity Frameworks 6 新的异步功能来保存对数据库的更改。我从 ASP.NET MVC 应用程序中使用它。直接返回 _repository.Commit() 是什么意思?
  • 我的意思是 MethodUnderTest 可能是 return _repository.Commit(); 如果你删除了 async 修饰符,所以如果你没有存根 _repository.Commit() 它只会在你的测试中返回一个空任务。跨度>
  • OK.. 这个例子有点小。我在 MethodUnderTest 中有多个等待,所以我不能只为 Commit() 删除 async 关键字

标签: c# unit-testing task-parallel-library async-await


【解决方案1】:

您需要退货; async Task 方法永远不能返回 null

T 无关紧要。如果需要,您可以将 static readonly Task SuccessTask = Task.FromResult&lt;object&gt;(null); 声明为辅助常量。我的 AsyncEx 库中有 similar constants

【讨论】:

    【解决方案2】:

    如果您的目标是 .NET Framework 4.6 或更高版本,您现在可以使用稍短一些的.Returns(Task.CompletedTask)

    【讨论】:

      猜你喜欢
      • 2019-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      • 1970-01-01
      • 2019-01-22
      • 2016-01-26
      相关资源
      最近更新 更多