当用户在活动页面上输入他们的电子邮件地址时,我们需要添加活动提醒。事件是另一个域对象。我们最初的想法是创建一个Customer域对象和相关的CustomerService:
public class CustomerService {
public void AddEventReminder(string emailAddress, int eventId) {
var customer = new Customer(emailAddress);
customer.AddEmailReminder(eventId);
}
}
我们如何在单元测试中验证确实在新客户上调用了AddEmailReminder方法?
我的想法:
单独注意(可能是相关的),我们如何确定哪个是聚合根?我们已经随意决定了客户,但它同样可以成为事件。我已阅读并理解有关聚合根的文章,但在这种情况下还不清楚。
答案 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,并且您可以通过特定客户检索,编辑和保留事件的唯一方法。这对我来说听起来有点不对。
唯一剩下的可能性是它们是独立的根源。这也意味着它们只是松散地相互连接,并且您需要某种域服务来为客户或事件的客户查找事件。