我认为您应该返回第一个或默认客户:
mock.Setup(m => m.GetById(IsAny<int>())).Returns<int>(
id =>
customersRepo.FirstOrDefault(c => c.Id == id)
);
另请记住,您不需要在模拟中重新实现存储库逻辑(这很奇怪且非常脆弱)。它是模拟的。您可以在没有任何逻辑的情况下模拟您想要的任何结果:
mock.Setup(m => m.GetById(42)).Returns<int>(new Customer { Id = 42 });
使用模拟来验证交互 - 即您的存储库的客户端使用预期参数调用预期方法。
如果你想测试某个服务的业务逻辑,那么服务就是一个被测系统(SUT),你不应该模拟它。但是如果你的服务既有业务逻辑又有数据访问逻辑,那么它做的事情就太多了。将数据访问逻辑提取到某个存储库类,它将实现接口:
public interface ICustomerRepository
{
Customer GetById(int id);
// other methods related to customr data access
}
然后让你的服务依赖这个接口(依赖倒置):
public class YourService
{
private readonly ICustomerRepository _repository;
// dependency injection
public YourService(ICustomerRepository repository)
{
_repository = repository;
}
public void ExecuteSomeBusinessLogic()
{
// your code will go here
}
}
然后为服务编写测试。因此服务需要依赖项(客户存储库),您应该模拟此依赖项。并验证服务是否如您所愿与依赖项交互。例如,在您的 ExecuteSomeBusinessLogic 测试中,我们应该检查服务是否会要求 id 等于 42 的客户(是的,奇怪的业务逻辑):
[Test]
public void ShouldPerformGoodStuffWhenCustomerFound()
{
// Arrange
var mockRepository = new Mock<ICustomerRepository>();
mockRepository.Setup(r => r.GetById(42)).Returns(new Customer { Id = 42 });
var service = new YourService(mockRepository.Object);
// Act
service.ExecuteSomeBusinessLogic();
// Assert
mockRepository.VerifyAll();
// check other stuff
}
如果您要在数据库中找不到自定义的情况下编写测试,只需设置不同的返回:
mockRepository.Setup(r => r.GetById(42)).Returns(null);