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