2010-01-06 147 views
3

我們有要求在用戶在活動頁面上輸入他們的電子郵件地址時添加事件提醒。事件是另一個域對象。我們最初的想法是創建一個Customer領域對象和相關的CustomerService:單元測試域對象

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

我們如何能在一個單元測試驗證AddEmailReminder方法確實呼籲新客戶?

我的想法:

  1. 使用一個工廠來創建客戶。這種氣味是因爲我認爲你只能在對象創建中存在一些複雜性的情況下使用工廠。
  2. 錯誤代碼。也許有更好的方法來做到這一點?
  3. 莫克魔法。

在另一個筆記(可能是相關的)上,我們如何決定這裏的聚合根?我們已經任意決定了客戶,但它同樣可以是事件。我已閱讀並理解有關聚合根源的文章,但在這種情況下還不清楚。

回答

6

在這種情況下,我會在創建客戶的服務中創建一個受保護的方法,在測試中使用匿名內部類重寫該方法,並使其返回一個模擬客戶對象。然後,您可以在模擬的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#的知識,但它應該說明這一點):在向客服API

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); 
} 
2

思考

是否有任何爲什麼您決定將此操作封裝在CustomerService中的特定原因?這看起來有點Anemic給我。它可能直接封裝在客戶上嗎?

也許你忽略了向客服代碼示例把事情簡單化的東西...

但是,如果你一定要,更改簽名採取客戶實例解決了這個問題:

public void AddEventReminder(Customer customer, int eventId) 

但話又說回來,一個Int32算不上域對象,所以它的簽名確實應該

public void AddEventReminder(Customer customer, Event event) 

現在的問題是這種方法是否增加任何價值?

哪一個是聚合根?

沒有一個,我會想。一個聚合根表明您管理的孩子只有通過根,那是沒有意義在這種情況下,無論哪種方式。

考慮的選項:

如果您事件的根源,這將意味着你可以有不CustomerRepository,唯一的方式,你可以檢索,編輯和堅持一個客戶將是通過事件。這聽起來很不對勁。

如果您以客戶爲根,您可以沒有EventRepository,並且唯一可以通過特定客戶檢索,編輯和保留事件的方法。這聽起來對我來說是錯誤的。

唯一剩下的可能性是它們是分開的根。這也意味着它們只是鬆散地相互連接,並且您需要某種域服務來查找客戶的事件或客戶的事件。

+0

該域服務方法的要點在於,它直接從已收到包含電子郵件地址和事件ID的dto的應用程序服務中調用。我認爲域對象應該只處理完整的對象,所以域服務應該處理這個問題。我不明白爲什麼它是貧血意味着它不應該繼續在域服務上,如果有什麼我會認爲這是相反的方式,因爲域對象都是關於邏輯的。重新聚合根,我同意他們都是聚合根,我問的問題是哪個聚合根負責協會? – JontyMC 2010-01-07 11:07:52

+0

...雖然有趣的答案。如果我要更改簽名,將創建客戶聚合根負責的代碼是什麼?也許這是更相關的問題。 – JontyMC 2010-01-07 11:09:42

+0

我懷疑服務是從應用程序層映射的。但是,在這種情況下,它不是一個域服務 - 它是一個應用層服務,屬於該層。在這種情況下,我認爲你需要一個可以根據電子郵件地址查找現有客戶的抽象工廠(可能是一個CustomerRepository)。 – 2010-01-07 11:35:55