Search code examples
unit-testingdomain-driven-designmoqaggregateroot

Unit testing domain objects


We have a requirement to add an event reminder when a user enters their email address on an event page. Event is another domain object. Our initial thought was to create a Customer domain object and related CustomerService:

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

How can we verify in a unit test that the AddEmailReminder method was indeed called on the new customer?

My thoughts:

  1. Use a factory to create the customer. This smells because I thought you were only supposed to use factory where there was some complexity in the object creation.
  2. Bad code. Maybe there is a better way to do this?
  3. Moq magic.

On a separate note (maybe it is related), how do we decide which is the aggregate root here? We have arbitrarily decided the customer is, but it could equally be the event. I have read and understand articles on aggregate roots, but it is unclear in this scenario.


Solution

  • In cases like this I would create a protected method in the service that creates the customer, in the test override that method it with anonymous inner class, and make it return a mock Customer object. Then you can verify on the mock Customer object that AddEmailReminder was called. Something like:

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

    and in the test (assume limited C# knowledge, but it should illustrate the point):

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