DDD рекомендует, чтобы объекты домена всегда находились в допустимом состоянии. Агрегатные корни отвечают за гарантию инвариантов и Фабрики для сборки объектов со всеми необходимыми частями, чтобы они были инициализированы в допустимом состоянии.
Однако это сильно усложняет задачу создания простых изолированных модульных тестов.
Предположим, у нас есть BookRepository, содержащий книги. Книга имеет:
- Автор
- Категория
- список книжных магазинов, в которых можно найти книгу
Это обязательные атрибуты: у книги должен быть автор, категория и хотя бы книжный магазин, в котором можно купить книгу. Скорее всего, будет BookFactory, так как это довольно сложный объект, и Factory будет инициализировать Книгу, по крайней мере, со всеми упомянутыми атрибутами. Возможно, мы также сделаем конструктор Book закрытым (а Factory вложенным), чтобы никто, кроме Factory, не мог создать экземпляр пустой книги.
Теперь мы хотим протестировать метод BookRepository, который возвращает все книги. Чтобы проверить, возвращает ли метод книги, мы должны настроить тестовый контекст (этап Arrange в терминах AAA), где некоторые книги уже находятся в репозитории.
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);
}
Учитывая, что единственным инструментом в нашем распоряжении для создания объектов Book является Factory, модульный тест теперь использует и зависит от Factory и косвенно от Category, Author и Store, поскольку нам нужны эти объекты для создания Book и последующего размещения его в тестовый контекст.
Считаете ли вы, что это зависимость так же, как в модульном тесте службы мы будем зависеть, скажем, от репозитория, который будет вызывать служба?
Как бы вы решили проблему повторного создания целого кластера объектов, чтобы иметь возможность протестировать простую вещь? Как бы вы разорвали эту зависимость и избавились от всех этих атрибутов Book, которые нам не нужны в нашем тесте? Используя макеты или заглушки?
Если вы смоделируете то, что содержит репозиторий, какие макеты/заглушки вы бы использовали, в отличие от того, когда вы смоделируете что-то, с чем тестируемый объект разговаривает или потребляет ?