1

假设我有以下要测试的功能:

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() 调用以返回硬编码的用户对象。

这是最好的方法吗?我猜你可能会说第二种实现更干净,因为所有数据访问都是通过存储库完成的,而不是隐藏在属性中。

4

2 回答 2

0

为什么您不希望您的单元测试访问您的数据库?如果您使用 MBUnit 编写测试用例,您只需使用 RollBack 属性标记单元测试,对数据库的任何更改都将回滚。

我一直更喜欢编写针对业务层但实际上 ping 数据库的单元测试用例,以便单元测试与应用程序本身将使用的最相似。

于 2009-04-01T14:14:35.473 回答
0

定义您自己的类似 Order 的接口,该接口提供您需要的基本功能,并将其用作 CancelOrder 方法的参数类型:

interface Order {
  public void Status(...); // or property
  public string UserEmail():
} 

然后创建该接口的委托实现,例如 SubsonicOrder,它调用数据库。在测试中使用存根实现。我意识到您可能需要一个更丰富的 Order 接口模型;这只是一个例子。

如果需要,对电子邮件服务执行相同的操作(可能通过构造函数或服务定位器进行依赖注入)。

于 2009-03-28T09:05:06.717 回答