DDD recommends that the domain objects should be in a valid state at any time. Aggregate roots are responsible for guaranteeing the invariants and Factories for assembling objects with all the required parts so that they are initialized in a valid state.
However this seems to complicate the task of creating simple, isolated unit tests a lot.
Let's assume we have a BookRepository that contains Books. A Book has :
- an Author
- a Category
- a list of Bookstores you can find the book in
These are required attributes : a book has to have an author, a category and at least a book store you can buy the book from. There's likely to be a BookFactory since it is quite a complex object, and the Factory will initialize the Book with at least all the mentioned attributes. Maybe we'll also make the Book constructor private (and the Factory nested) so that no one can instantiate an empty Book except the Factory.
Now we want to unit test a method of the BookRepository that returns all the Books. To test if the method returns the books, we have to set up a test context (the Arrange step in AAA terms) where some Books are already in the Repository.
In C# :
[Test]
public void GetAllBooks_Returns_All_Books()
{
//Lengthy and messy Arrange section
BookRepository bookRepository = new BookRepository();
Author evans = new Author("Evans", "Eric");
BookCategory category = new BookCategory("Software Development");
Address address = new Address("55 Plumtree Road");
BookStore bookStore = BookStoreFactory.Create("The Plum Bookshop", address);
IList<BookStore> bookstores = new List<BookStore>() { bookStore };
Book domainDrivenDesign = BookFactory.Create("Domain Driven Design", evans, category, bookstores);
Book otherBook = BookFactory.Create("other book", evans, category, bookstores);
bookRepository.Add(domainDrivenDesign);
bookRepository.Add(otherBook);
IList<Book> returnedBooks = bookRepository.GetAllBooks();
Assert.AreEqual(2, returnedBooks.Count);
Assert.Contains(domainDrivenDesign, returnedBooks);
Assert.Contains(otherBook, returnedBooks);
}
Given that the only tool at our disposal to create Book objects is the Factory, the unit test now uses and is dependent on the Factory and inderectly on Category, Author and Store since we need those objects to build up a Book and then place it in the test context.
Would you consider this is a dependency in the same way that in a Service unit test we would be dependent on, say, a Repository that the Service would call ?
How would you solve the problem of having to re-create a whole cluster of objects in order to be able to test a simple thing ? How would you break that dependency and get rid of all these Book attributes we don't need in our test ? By using mocks or stubs ?
If you mock up things a Repository contains, what kind of mock/stubs would you use as opposed to when you mock up something the object under test talks to or consumes ?