问题描述
在测试一种使用异步存储库方法的服务方法时遇到问题。
存储库层
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-对象引用未设置为对象的实例
不确定我想念什么。
解决方法
此答案的目的是从聊天讨论中获取有价值的信息。
正如OP所说的,NullReferenceException
已被抛出以下行:
_repo.SaveAsync(model).Wait();
_repo
试图通过以下方式在单元测试中初始化:
var mockRepo = Mock.Get(new Repo());
那不是正确的方法。请检查Mock.Get
中的documentation,以了解何时应使用它以及用于什么目的。
_repo
应该用以下方式初始化:
var mockRepo = new Mock<IRepo>();
在更改模拟创建后,OP有以下观察结果:
但是,我放弃了用于回购构建的DI设置
简而言之:这就是重点。
每当您对组件进行单元测试时,您都将尝试模拟(简化和模仿)其所有依赖项。它需要依赖 stub 和 spy 来验证在某些情况下已调用了其中之一,但是模拟对象的具体实现并不重要。 / p>
在这种特殊情况下,这意味着服务层不想依赖于具体的Repository实例。它只需要一个仓库,它可以捕获调用参数并可以验证其调用。
仅供参考:测试terminologies
- 虚拟:返回伪造数据 的简单代码
- 伪造:可以使用快捷方式的有效的替代
- 存根:具有预定义数据的自定义逻辑
- 模拟:具有期望(交互式存根)的自定义逻辑
- 填充:运行时自定义逻辑
- 间谍:拦截器以记录通话