我正在使用.net mvc3构建简单的应用程序。我写了几个测试用例,我对其中一个有问题。我使用Moq来模拟我的域名服务,我有两种方法:
List<Customer> customersRepo =
{
new Customer{
Id = 0,
Name = "Jojo"
},
new Customer{
Id = 1,
Name = "John"
}
}
mock.Setup(m => m.GetByName(IsAny<string>())).Returns<string>(
n =>
customersRepo.Where(c => c.Name == n)
);
mock.Setup(m => m.GetById(IsAny<int>())).Returns<int>(
n=>
customersRepo.Where(c => c.Id == n)
);
问题是,当我使用模拟对象的方法按名称获取客户时,我得到了我要求的那个,但是当我尝试通过id获取时,我总是从模拟对象获取空对象..我试过两个id 0和1 ..可能是什么问题?
由于
答案 0 :(得分:1)
我认为您应该先退回或默认客户:
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);
答案 1 :(得分:0)
我实际上只是改变了一点我的基础设施..现在我的服务获取构造函数中的DataSource接口对象..这是独立的数据源,它依赖于它来获取客户对象,ofc。在它检查业务规则并完成用户输入所需的任何卫生之后..所以现在,我将在单元测试中模拟我的数据源(带有客户对象的列表)并使用这个模拟仓库来提供我的服务实例客户对象..这样我就可以测试我已编码的服务业务逻辑的正确性。以前我将服务与特定数据存储(即使用EF DbContext的数据库)相结合,并且在单元测试中使用该服务有点困难,因为它已经与数据库耦合,但我不想改变和恢复db状态只是为了执行我的单元测试,所以我想用简单的客户对象列表来模拟数据存储。感谢您的努力,帮助我:)