8

DDD đề xuất rằng các đối tượng miền phải ở trạng thái hợp lệ bất kỳ lúc nào. Các rễ tổng hợp chịu trách nhiệm đảm bảo các bất biến và các nhà máy để lắp ráp các đối tượng với tất cả các bộ phận cần thiết để chúng được khởi tạo ở trạng thái hợp lệ.Làm thế nào để giữ cho các bài kiểm tra đơn vị của bạn đơn giản và cô lập mà vẫn đảm bảo các bất biến DDD?

Tuy nhiên điều này dường như làm phức tạp nhiệm vụ tạo đơn vị, kiểm tra đơn vị bị cô lập rất nhiều.

Giả sử chúng tôi có BookRepository chứa Sách. Một cuốn sách có:

  • một Tác giả
  • một loại
  • một danh sách các tiệm sách, bạn có thể tìm thấy những cuốn sách trong

Những thuộc tính được yêu cầu: một cuốn sách phải có một tác giả, một danh mục và ít nhất một cửa hàng sách bạn có thể mua sách từ đó. Có khả năng là một BookFactory vì nó là một đối tượng khá phức tạp và Nhà máy sẽ khởi tạo Sách với ít nhất tất cả các thuộc tính được đề cập. Có lẽ chúng ta cũng sẽ làm cho hàm tạo Book riêng tư (và Factory được lồng nhau) để không ai có thể tạo ra một Book rỗng trừ Factory.

Bây giờ, chúng tôi muốn đơn vị kiểm tra một phương pháp của BookRepository trả về tất cả các Sách. Để kiểm tra nếu phương thức trả về các sách, chúng ta phải thiết lập một ngữ cảnh thử nghiệm (bước Sắp xếp theo các điều khoản AAA) trong đó một số Sách đã có trong Kho lưu trữ.

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

Cho rằng công cụ duy nhất mà chúng ta có để tạo ra Book đối tượng là các nhà máy, các đơn vị kiểm tra bây giờ sử dụng và phụ thuộc vào các nhà máy và inderectly trên Danh mục, tác giả và cửa hàng kể từ chúng ta cần những đối tượng đó để xây dựng một cuốn sách và sau đó đặt nó vào bối cảnh thử nghiệm.

Bạn có cho rằng đây là phụ thuộc giống như cách kiểm tra đơn vị dịch vụ mà chúng tôi sẽ phụ thuộc vào, một Kho lưu trữ mà Dịch vụ sẽ gọi?

Làm cách nào bạn giải quyết được vấn đề phải tạo lại toàn bộ cụm đối tượng để có thể thử nghiệm một điều đơn giản? Làm thế nào bạn sẽ phá vỡ sự phụ thuộc đó và loại bỏ tất cả các thuộc tính Sách mà chúng ta không cần trong thử nghiệm của chúng ta? Bằng cách sử dụng mocks hoặc khai?

Nếu bạn giả lập điều một Repository chứa, những loại giả/cuống bạn sẽ sử dụng như trái ngược với khi bạn thử lên một cái gì đó đối tượng được kiểm tra cuộc đàm phán để hoặc tiêu thụ?

Trả lời

4

Hai điều:

  • Sử dụng các đối tượng giả trong các bài kiểm tra. Bạn hiện đang sử dụng các vật thể cụ thể.

  • Liên quan đến việc thiết lập phức tạp, tại một số thời điểm bạn sẽ cần một số sách hợp lệ. Trích xuất logic này thành phương thức thiết lập, để chạy trước mỗi lần kiểm tra. Có phương pháp thiết lập đó tạo một bộ sưu tập sách hợp lệ và v.v.

"Làm thế nào bạn sẽ giải quyết vấn đề của phải tái tạo một cụm toàn bộ đối tượng để có thể kiểm tra một điều đơn giản? Làm thế nào bạn sẽ phá vỡ rằng sự phụ thuộc và loại bỏ tất cả các thuộc tính Sách chúng tôi không cần trong thử nghiệm của chúng tôi? Bằng cách sử dụng mocks hoặc khai? "

Đối tượng giả sẽ cho phép bạn thực hiện việc này. Nếu một bài kiểm tra chỉ cần một cuốn sách với một tác giả hợp lệ, đối tượng giả của bạn sẽ chỉ định tác giả đó, các thuộc tính khác sẽ được mặc định. Vì kiểm tra của bạn chỉ quan tâm đến một tác giả hợp lệ, không cần phải thiết lập các thuộc tính khác.

1

Cảm ơn Finglas vì câu trả lời. Tôi sử dụng mocks trong các bài kiểm tra khác nhưng chủ yếu cho thử nghiệm tương tác, không phải để thiết lập bối cảnh thử nghiệm. Tôi không chắc liệu loại vật thể rỗng này chỉ với những giá trị cần thiết có thể được gọi là giả lập hay không và liệu có nên sử dụng chúng không.

Tôi đã tìm thấy điều gì đó thú vị và khá gần với vấn đề tại địa chỉ xunitpatterns.com của Gerard Meszaros. Ông mô tả mùi mã của việc thiết lập thử nghiệm dài và phức tạp là Irrelevant Information, với các giải pháp có thể là Creation Methods hoặc Dummy Objects. Tôi không hoàn toàn được bán trên Dummy Object của mình mặc dù, trong ví dụ của tôi nó sẽ buộc tôi phải có một giao diện IBook (ugh) để thực hiện một cuốn sách giả với một nhà xây dựng rất đơn giản và bỏ qua tất cả các logic tạo Factory.

Tôi đoán là sự kết hợp giữa các phương pháp tạo khung cách ly và phương pháp tạo có thể giúp tôi làm rõ và đơn giản hóa các thử nghiệm của mình.

1

Bạn có thể muốn thử Trình tạo dữ liệu thử nghiệm. Đẹp post from Nat Pryce.

Điều này có thể hữu ích nếu bạn không muốn đi tuyến đường của mocks. Nó có thể tóm tắt tất cả những phương pháp nhà máy xấu xí đó. Ngoài ra, bạn có thể cố gắng đẩy các nhà xây dựng được sử dụng trong mã sản xuất của bạn.

3

Đối với các thử nghiệm đơn vị thuần túy, mocks và sơ đồ chắc chắn là giải pháp. Nhưng kể từ khi bạn đang đi sau một nhiều hơn các bài kiểm tra mức độ hội nhập, và mocks (hoặc cuống hoặc bất cứ điều gì) không giải quyết vấn đề của bạn, bạn thực sự có hai lựa chọn hợp lý:

  • tạo nhà máy thử nghiệm để giúp bạn thiết up các dữ liệu bạn cần. Đây có thể là kiểm tra cụ thể, không chỉ xây dựng một hiệu sách, mà còn có một sách được thiết lập hợp lý. Bằng cách đó, bạn nén mã thiết lập của mình thành một hoặc hai dòng và sử dụng chúng cho các thử nghiệm khác. Mã này có thể phát triển để tạo ra các kịch bản khác nhau cần thiết cho các bài kiểm tra kiểu tích hợp.

  • tạo thiết lập thử nghiệm đồ đạc thử nghiệm. Đây là những bộ dữ liệu nhỏ nhưng đầy khái niệm cho các thử nghiệm của bạn để sử dụng. Chúng thường được lưu trữ trong một số loại hình thức tuần tự hóa (xml, csv, sql) và được nạp vào đầu mỗi bài kiểm tra vào cơ sở dữ liệu của bạn để bạn có trạng thái hợp lệ. Họ thực sự chỉ là một nhà máy chung hoạt động bằng cách đọc các tệp tĩnh.

Nếu bạn sử dụng đồ đạc, bạn có thể sử dụng phương pháp tiếp cận một hoặc nhiều vật cố.Nếu bạn có thể lấy đi một bộ dữ liệu "chuẩn" cho hầu hết các bài kiểm tra đơn vị của mình, điều này sẽ đơn giản hơn, nhưng đôi khi điều đó tạo ra tập dữ liệu có quá nhiều bản ghi dễ hiểu hoặc đơn giản là không thể hiện phạm vi các tình huống bạn cần hỗ trợ. Một số vấn đề đòi hỏi nhiều bộ dữ liệu được kiểm tra kỹ lưỡng.

1

Có lẽ chúng ta cũng sẽ làm cho các nhà xây dựng Sách tư nhân (và các Nhà máy lồng nhau) để không ai có thể nhanh chóng một Book rỗng ngoại trừ Nhà máy.

Nhà xây dựng tư nhân Book là nguồn gốc của sự cố của bạn.

Nếu bạn đặt bên trong của hàm xây dựng Book, nhà máy không cần phải lồng nhau. Sau đó, bạn được tự do làm cho nhà máy triển khai giao diện (IBookFactory) và bạn có thể đưa nhà máy sản xuất sách giả vào kho lưu trữ của mình.

Nếu bạn thực sự muốn đảm bảo rằng cuốn sách chỉ triển khai nhà máy tạo ra các trường hợp, thêm một phương pháp để kho của bạn chấp nhận các đối số nhà máy cần:

public class BookRepository { 

    public IBookFactory bookFactory; 

    public BookRepository(IBookFactory bookFactory) { 
     this.bookFactory = bookFactory; 
    } 

    // Abbreviated list of arguments 
    public void AddNew(string title, Author author, BookStore bookStore) { 
     this.Add(bookFactory.Create(title, author, bookStore)); 
    } 

} 
0

II có thể bị sai lệch bởi vì tôi đã bắt đầu học tập DDD cùng bên với CQRS. Nhưng tôi không chắc chắn bạn vẽ ranh giới chính xác. Tổng hợp chỉ nên biết về những bất biến của nó. Bạn nói một cuốn sách có một tác giả. Có nhưng cuốn sách không có bất biến về tên của tác giả. vì vậy chúng tôi có thể hình dung cuốn sách tổng hợp như sau:

public class Book 
{ 
    public Guid _idAuthor; 

    public Book(Guid idAuthor) 
    { 
     if(idAuthor==guid.empty) throw new ArgumentNullException(); 

     _idAuthor = idAuthor; 
    } 
} 

Trong khi đó, các tác giả có một bất biến về tác giả của nó:

public class Author 
{ 
    public string _name; 

    public Book(string name) 
    { 
     if(name==nullorEmpty) throw new ArgumentNullException(); 

     _name= name; 
    } 
} 

Phía truy vấn mặc dù sẽ có thể có một nhu cầu cho cả cuốn sách thông tin tên và tên tác giả, nhưng đây là một truy vấn và có thể không phù hợp để kiểm tra đơn vị IMO.

Nếu bạn cần có thể thêm vào thư viện của mình, chỉ cần đặt khi tác giả của họ có chữ 'e' trong đó, thì toàn bộ cuộc thảo luận khác, nhưng từ những gì tôi hiểu, bạn không cần nó ngay bây giờ .

Khi tạo tổng hợp Đặt đơn vị kiểm tra đơn vị của bạn trở nên đơn giản hơn, bởi vì bạn tập trung vào mặt viết và trên những bất biến thực sự.

Các vấn đề liên quan