单元测试域对象

时间:2010-01-06 18:42:32

标签: unit-testing domain-driven-design moq aggregateroot

当用户在活动页面上输入他们的电子邮件地址时,我们需要添加活动提醒。事件是另一个域对象。我们最初的想法是创建一个Customer域对象和相关的CustomerService:

public class CustomerService {
    public void AddEventReminder(string emailAddress, int eventId) {
       var customer = new Customer(emailAddress);
       customer.AddEmailReminder(eventId);
    }
}

我们如何在单元测试中验证确实在新客户上调用了AddEmailReminder方法?

我的想法:

  1. 使用工厂创建客户。这有点味道,因为我认为你只应该使用工厂,而对象的创建有一些复杂性。
  2. 错误的代码。也许有更好的方法来做到这一点?
  3. Moq magic。
  4. 单独注意(可能是相关的),我们如何确定哪个是聚合根?我们已经随意决定了客户,但它同样可以成为事件。我已阅读并理解有关聚合根的文章,但在这种情况下还不清楚。

2 个答案:

答案 0 :(得分:6)

在这种情况下,我会在创建客户的服务中创建一个受保护的方法,在测试中使用匿名内部类覆盖该方法,并使其返回模拟Customer对象。然后,您可以在模拟Customer对象上验证是否已调用AddEmailReminder。 类似的东西:

public class CustomerService {
    public void AddEventReminder(string emailAddress, int eventId) {
       var customer = createCustomer(emailAddress);
       customer.AddEmailReminder(eventId);
    }

    protected Customer createCustomer(string emailAddress) {
       return new Customer(emailAddress);
    }
}

并且在测试中(假设有限的C#知识,但它应该说明这一点):

void testCustomerCreation() {
    /* final? */ Customer mockCustomer = new Customer("email");
    CustomerService customerService = new CustomerService() {
       protected Customer createCustomer(string emailAddress) {
           return mockCustomer;
       }            
    };

    customerService.AddEventReminder("email", 14);

    assertEquals(mockCustomer.EventReminder() /* ? */, 14);
}

答案 1 :(得分:2)

关于CustomerService API的想法

您是否有任何特殊原因决定将此操作封装在CustomerService中?这对我来说有点Anemic。它可能直接封装在客户身上吗?

也许您遗漏了一些CustomerService代码示例来简化事情......

但是,如果必须,更改签名以获取Customer实例可以解决问题:

public void AddEventReminder(Customer customer, int eventId)

但是再一次,Int32很难成为域对象,所以签名应该是

public void AddEventReminder(Customer customer, Event event)

现在的问题是这个方法是否会添加任何值?

哪个是合计根?

我想他们都不是。聚合根表示您通过根管理的子项,在这种情况下无论如何都没有意义。

考虑选项:

如果您将Event设为root,则意味着您可能没有CustomerRepository,并且您可以通过事件检索,编辑和保留客户的唯一方法。这对我来说听起来很不对。

如果您将Customer作为root用户,则您可以没有EventRepository,并且您可以通过特定客户检索,编辑和保留事件的唯一方法。这对我来说听起来有点不对。

唯一剩下的可能性是它们是独立的根源。这也意味着它们只是松散地相互连接,并且您需要某种域服务来为客户或事件的客户查找事件。