7

Chúng tôi đã sử dụng Simple Injector với thành công tốt, trong một ứng dụng khá đáng kể. Chúng tôi đã sử dụng tiêm xây dựng cho tất cả các lớp sản xuất của chúng tôi, và cấu hình Simple Injector để điền tất cả mọi thứ, và tất cả mọi thứ của đào.Sử dụng DI container trong các bài kiểm tra đơn vị

Chúng tôi đã không sử dụng Simple Injector để quản lý cây phụ thuộc cho các thử nghiệm đơn vị của chúng tôi. Thay vào đó, chúng tôi đã làm mới mọi thứ theo cách thủ công.

Tôi vừa dành một vài ngày làm việc thông qua một quá trình tái cấu trúc chính, và gần như tất cả thời gian của tôi là sửa chữa những cây phụ thuộc xây dựng thủ công này trong các bài kiểm tra đơn vị của chúng tôi.

Điều này khiến tôi tự hỏi - có ai có bất kỳ mẫu nào họ sử dụng để định cấu hình các cây phụ thuộc mà họ sử dụng trong các thử nghiệm đơn vị không? Đối với chúng tôi, ít nhất, trong các thử nghiệm của chúng tôi cây phụ thuộc của chúng tôi có xu hướng khá đơn giản, nhưng có rất nhiều trong số họ.

Bất kỳ ai cũng có phương pháp họ sử dụng để quản lý các phương pháp này?

+0

Không chắc chắn bạn đang tìm kiếm mẫu nào. Tại sao không chỉ làm cho các thùng chứa của bạn trong khởi tạo thử nghiệm (constructor cho xunit, ví dụ)? Các mô hình là đơn giản - thành phần. – Artyom

+1

Nếu bạn thực sự quan tâm đến các mẫu thử nghiệm đơn vị, bạn nên đọc [Mẫu thử nghiệm xUnit] (https://www.amazon.co.uk/xUnit-Test-Patterns-Refactoring-Code-ebook/dp/B004X1D36K/ref = dp_kinw_strp_1). – Steven

Trả lời

12

Để kiểm tra đơn vị thực sự (tức là những thử nghiệm chỉ kiểm tra một lớp và giả định tất cả các lớp phụ thuộc), việc sử dụng khung DI sẽ không có ý nghĩa gì. Trong những thử nghiệm này:

  • nếu bạn thấy rằng bạn có rất nhiều mã lặp đi lặp lại cho new ing lên một thể hiện của lớp học của bạn với tất cả các mocks bạn đã tạo ra, một chiến lược hữu ích là tạo ra tất cả các mocks của bạn và tạo cá thể cho đối tượng thử nghiệm trong phương thức thiết lập của bạn (tất cả có thể là trường cá thể riêng), và sau đó mỗi vùng "sắp xếp" của từng thử nghiệm chỉ cần gọi mã Setup() thích hợp trên các phương thức cần thiết. Bằng cách này, bạn kết thúc chỉ với một tuyên bố new PersonController(...) cho mỗi lớp thử nghiệm.
  • nếu bạn cần tạo nhiều đối tượng miền/dữ liệu, thật hữu ích khi tạo các đối tượng Builder bắt đầu bằng các giá trị sane để thử nghiệm. Vì vậy, thay vì gọi một hàm tạo lớn trên mã của bạn, với một loạt các giá trị giả, bạn chủ yếu chỉ gọi, ví dụ: var person = new PersonBuilder().Build(), có thể chỉ với một vài phương pháp gọi cho các phần dữ liệu mà bạn đặc biệt quan tâm trong bài kiểm tra đó . Bạn cũng có thể quan tâm AutoFixture, nhưng tôi chưa bao giờ sử dụng nó vì vậy tôi không thể xác minh cho nó.

Nếu bạn đang viết hội nhập kiểm tra, nơi bạn cần phải kiểm tra sự tương tác giữa một số bộ phận của hệ thống, nhưng bạn vẫn cần để có thể thử phần cụ thể, xem xét việc tạo lớp Builder cho dịch vụ của bạn, để bạn có thể nói, ví dụ var personController = new PersonControllerBuilder.WithRealDatabase(connection).WithAuthorization(new AllowAllAuthorizationService()).Build().

Nếu bạn đang viết các bài kiểm tra đầu cuối hoặc "kịch bản", nơi bạn cần kiểm tra toàn bộ hệ thống, thì bạn nên thiết lập khung DI, tận dụng cùng mã cấu hình mà sản phẩm thực của bạn sử dụng. Bạn có thể thay đổi cấu hình một chút để cung cấp cho mình khả năng kiểm soát chương trình tốt hơn đối với những thứ như người dùng nào đăng nhập và như vậy. Bạn vẫn có thể tận dụng các lớp xây dựng khác mà bạn đã tạo để xây dựng dữ liệu.

var user = new PersonBuilder().Build(); 
using(Login.As(user)) 
{ 
    var controller = Container.Get<PersonController>(); 
    var result = controller.GetCurrentUser(); 
    Assert.AreEqual(result.Username, user.Username) 
} 
+1

Tôi tin rằng [Object Mother] (http://xunitpatterns.com/Test%20Helper.html) là tên của mẫu builder trong trường hợp kiểm thử đơn vị. Câu trả lời tốt đẹp btw. +1 – Steven

+0

Câu trả lời đối diện tại: https://softwareengineering.stackexchange.com/questions/140992/is-dependency-injection-essential-for-unit-testing – sotn

+0

@sotn: Điều đó dường như không phải là cùng một câu hỏi và Tôi không thấy bất kỳ câu trả lời nào xuất hiện để mâu thuẫn với điều này. Bạn có thể liên kết trực tiếp với câu trả lời mà bạn đang nói đến và giải thích cách "đối diện" với điều này không? – StriplingWarrior

6

Không sử dụng hộp chứa DI trong các thử nghiệm đơn vị của bạn. Trong các bài kiểm tra đơn vị, bạn cố gắng kiểm tra một lớp hoặc mô-đun trong sự cô lập, và có rất ít sử dụng cho một thùng chứa DI trong khu vực đó.

Mọi thứ khác với thử nghiệm tích hợp, vì bạn muốn kiểm tra xem các thành phần trong hệ thống của bạn tích hợp và hoạt động cùng nhau như thế nào. Trong trường hợp đó, bạn thường sử dụng cấu hình DI sản xuất của mình và hoán đổi một số dịch vụ của bạn cho các dịch vụ giả mạo (chẳng hạn như MailService) nhưng hãy gắn bó với thực tế nhất có thể.Trong trường hợp này, bạn sử dụng vùng chứa của mình để giải quyết toàn bộ đồ thị đối tượng.

Mong muốn sử dụng hộp chứa DI trong các thử nghiệm đơn vị cũng thường xuất phát từ các mẫu không hiệu quả. Ví dụ, trong trường hợp bạn cố gắng tạo lớp dưới sự kiểm tra với tất cả các phụ thuộc của nó trong mỗi bài kiểm tra, bạn sẽ nhận được rất nhiều mã khởi tạo trùng lặp, và một chút thay đổi trong lớp của bạn trong bài kiểm tra có thể trong trường hợp đó gợn qua hệ thống và yêu cầu bạn thay đổi hàng chục bài kiểm tra đơn vị. Điều này rõ ràng là nguyên nhân gây ra vấn đề bảo trì.

Một mô hình đã giúp tôi thực hiện điều này rất nhiều trong quá khứ là việc sử dụng phương pháp nhà máy cụ thể cho từng lớp thử nghiệm đơn giản. Phương thức này tập trung vào việc tạo ra các lớp đang được kiểm tra và giảm thiểu số lượng các thay đổi cần phải được thực hiện khi các phụ thuộc của lớp dưới sự thay đổi thử nghiệm. Đây là cách phương thức nhà máy như vậy có thể trông giống như:

private ClassUnderTest CreateValidClassUnderTest(params object[] dependencies) { 
    return new ClassUnderTest(
     dependencies.OfType<ILogger>().SingleOrDefault() ?? new FakeLogger(), 
     dependencies.OfType<IMailSender>().SingleOrDefault() ?? new FakeMailer(), 
     dependencies.OfType<IEventPublisher>().SingleOrDefault() ?? new FakePublisher()); 
} 

Phương thức nhà máy này chứa một sự phụ thuộc. Mã trích xuất các phụ thuộc từ danh sách và trong trường hợp một phụ thuộc cụ thể bị thiếu, một triển khai giả mới sẽ được tiêm.

Tác phẩm này, vì trong hầu hết các thử nghiệm, bạn chỉ quan tâm đến một hoặc hai phụ thuộc. Các phụ thuộc khác được yêu cầu cho lớp hoạt động, nhưng không thú vị đối với thử nghiệm cụ thể. Do đó, phương pháp nhà máy cho phép bạn chỉ cung cấp các phụ thuộc thú vị cho thử nghiệm trong tầm tay, đồng thời loại bỏ nhiễu của các phụ thuộc không sử dụng. Do đó, phương pháp nhà máy cho phép bạn viết các bài kiểm tra sau:

public void Test() { 
    // Arrange 
    var logger = new ListLogger(); 

    var cut = CreateValidClassUnderTest(logger); 

    // Act 
    cut.DoSomething(); 

    // Arrange 
    Assert.IsTrue(logger.Count > 0);  
} 

Nếu bạn muốn tìm hiểu làm thế nào để viết Trustworthy và duy trì kiểm tra có thể đọc, tôi khuyên bạn nên đọc cuốn sách Roy Osherove của The Art of Testing Unit (ấn bản thứ hai). Điều này đã giúp tôi rất nhiều.

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