【问题标题】:Getting NullReferenceException while mocking Async method in Unit Test (Xunit - Moq)在单元测试中模拟异步方法时获取 NullReferenceException (Xunit - Moq)
【发布时间】:2020-12-01 00:00:29
【问题描述】:

我在测试一种使用异步存储库方法的服务方法时遇到问题。

存储层

public interface IRepo
{
    Task<Model> GetByIdAsync(string Id);
    Task SaveAsync(Model model);
}

服务层

void Process(string Id)
{
    var model = _repo.GetByIdAsync(Id).Result;
        
    model.Field1 = "update";
        
    _repo.SaveAsync(model).Wait();
}

针对服务层的单元测试

[Fact]
SUTServiceTest()
{
    //Arrange
    Model model = new Model();
    var mockRepo = Mock.Get(new Repo());

    mockRepo.Setup(x => x.GetByIdAsync(It.IsNotNull<string>()))
        .Returns(() => Task.FromResult(model));

    mockRepo.Setup(x => x.SaveAsync(It.IsAny<Model>()))
        .Callback<Model>((obj) => model = obj);

    var _service = new SUTService(mockRepo);

    //Act
    _service.Process("1");

    //Assert
    Assert.Equal("update", model.Field1);
}

我在_repo.SaveAsync(model).await(); 收到以下错误:

System.NullReferenceException - 对象引用未设置为对象的实例

不知道我错过了什么。

【问题讨论】:

  • 你能和我们分享一下.await()的实现吗?
  • @PeterCsala 在测试中我正在为等待的方法设置模拟。但以下供参考的是实现public async Task repoAsync(Model model) { await dbHelper.SaveAsync(model).ConfigureAwait(false); }
  • 又是我的错,是 .Wait(); 等待线程在执行后返回。
  • 将此行:var mockRepo = Mock.Get(new Repo()); 更改为:var mockRepo = new Mock&lt;IRepo&gt;();
  • @PeterCsala 这行得通。谢谢.. 但是,我失去了用于 Repo 构建的 DI 设置。

标签: unit-testing async-await moq xunit xunit.net


【解决方案1】:

此答案的目的是从聊天讨论中获取有价值的信息。

正如 OP 所说,NullReferenceException 已在以下行抛出:

_repo.SaveAsync(model).Wait();

_repo在单元测试中尝试如下初始化:

var mockRepo = Mock.Get(new Repo());

这不是正确的做法。请检查Mock.Getdocumentation 以了解何时应该使用它以及用于什么目的。

_repo 应按以下方式初始化:

var mockRepo = new Mock<IRepo>();

在更改模拟创建后,OP 有以下观察结果:

但是,我失去了用于回购构建的 DI 设置

简而言之:这就是重点。
每当您对组件进行单元测试时,您都会尝试模拟(简化和模仿)它的所有依赖项。它需要依靠 stubsspies 来验证在某些情况下调用了其中的哪一个,但被模拟对象的具体实现并不重要。

在这种特殊情况下,这意味着服务层不想依赖具体的存储库实例。它只需要一个repo,它可以捕获调用参数并可以验证它的调用。


仅供参考:测试terminologies

  • Dummy:返回虚假数据的简单代码
  • Fake:一种可行的替代品,可以走捷径
  • 存根:带有预定义数据的自定义逻辑
  • 模拟:带有期望的自定义逻辑(交互式存根)
  • Shim:自定义逻辑在运行时
  • 间谍拦截器记录通话

【讨论】:

    猜你喜欢
    • 2014-01-18
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多