假设我有以下要测试的功能:
public void CancelOrder(Order order)
{
order.Status = "Cancelled";
_emailService.SendEmail(order.User.Email, "Your order has been cancelled!");
}
现在,Order类是一个SubSonic生成的类,其上的User属性是延迟加载的,这意味着当我调用order.User.Email时,它实际上运行一个SQL语句来获取用户。
如果我想对此进行单元测试,我会遇到问题,因为我不希望我的单元测试到达我的数据库。
我目前的解决方案是将CancelOrder函数重构为:
public void CancelOrder(Order order)
{
order.Status = "Cancelled";
User user = _userRepository.GetByUserID(order.UserID);
_emailService.SendEmail(user.Email, "Your order has been cancelled!");
}
然后我可以存根_userRepository.GetUserByID()调用以返回硬编码的User对象。
这是最好的方法吗?我想你可以说第二个实现更干净,因为所有数据访问都是通过存储库完成的,而不是隐藏在属性中。
答案 0 :(得分:0)
定义您自己的类似订单的界面,它提供您需要的简单功能,并将其用作CancelOrder方法的参数类型:
interface Order {
public void Status(...); // or property
public string UserEmail():
}
然后创建该接口的委托实现,例如SubsonicOrder,调用数据库。在测试中使用存根实现。我意识到你可能需要一个更丰富的Order接口模型;这只是一个例子。
如果需要,请对电子邮件服务进行相同操作(可能通过构造函数或服务定位器依赖注入)。
答案 1 :(得分:0)
为什么不希望您的设备测试到达您的数据库?如果您使用MBUnit编写测试用例,则可以使用RollBack属性标记单元测试,并且将回滚对数据库的任何更改。
我一直希望编写以业务层为目标的单元测试用例,但实际上ping数据库,以便单元测试与应用程序本身将使用的最相似。