2009-05-04 26 views
6

Tôi đang cố gắng tìm hiểu sự tiêm phụ thuộc và gặp phải một vấn đề, khi đơn vị kiểm thử ứng dụng.Sự phụ thuộc của quá trình Tiêm phụ thuộc và thử nghiệm đơn vị

Tôi đang viết ứng dụng bảng điều khiển và vùng chứa được tạo và được khởi tạo trong Main(), có sẵn dưới dạng get-property trong Program.Container, vì vậy ở bất kỳ đâu trong ứng dụng của tôi, tôi có thể gọi Program.Container.Resolve<..>().

Tôi có một lớp ServiceValidator như thế này:

public class ServiceValidator 
{ 
    private readonly IConfiguration _configuration; 
    private readonly IService _service; 

    public ServiceValidator(IConfiguration configuration, IService service) 
    { 
     _configuration = configuration; 
     _service = service; 
    } 

Trong lớp khác tôi sử dụng

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>(); 
serviceValidator.VerifyVersion(); 

Đó là lời kêu gọi Program.Container.Resolve gây cho tôi những vấn đề trong các thử nghiệm đơn vị, vì nó không có đã được thiết lập.

Thực tiễn không tốt, để gọi giải quyết trên vùng chứa phải không? Tôi có thể tạo ra các ServiceValidator dụ trong Main() và vượt qua đối tượng xung quanh, nhưng điều đó có vẻ ngu ngốc vì nó sẽ gây ra rất nhiều tham số cho các đối tượng mà chỉ cần thông qua xung quanh để phương pháp tiếp theo.

Vì vậy, tôi đoán có thể chấp nhận gọi Resolve trong một lớp, nhưng sau đó vùng chứa phải được định cấu hình cho thử nghiệm đơn vị. Làm thế nào tôi nên làm điều đó, tôi nên di chuyển container đến một nơi khác hơn so với các lớp học chương trình? Bạn muốn giới thiệu gì?

Nếu vấn đề, tôi đang sử dụng Unity và C#

Cảm ơn :-)

Trả lời

8

Thực tiễn không tốt, để gọi giải quyết trên vùng chứa phải không?Tôi có thể tạo ra cá thể ServiceValidator trong Main() và truyền đối tượng xung quanh, nhưng điều đó có vẻ ngu ngốc vì nó sẽ gây ra rất nhiều tham số cho các đối tượng vừa được chuyển tới phương thức tiếp theo.

Khi bạn sử dụng tính năng tiêm phụ thuộc, bạn sẽ không cần truyền nhiều thông số cho đối tượng. Hàm khởi tạo của mỗi đối tượng chỉ nên có các tham số mà chính nó sử dụng trực tiếp - nó sẽ không biết về các phụ thuộc chuyển tiếp của các phụ thuộc trực tiếp của nó.

Vì vậy, nếu bạn có lớp X yêu cầu ServiceValidator, thì lớp X sẽ có tham số hàm tạo kiểu ServiceValidator. Sau đó, nếu một số lớp Y sử dụng lớp X, thì lớp Y sẽ có tham số khởi tạo của kiểu X. Lưu ý rằng Y không biết gì về về ServiceValidator, vì vậy bạn không cần phải chuyển ServiceValidator từ lớp này sang lớp khác - nơi duy nhất nơi nó được sử dụng là khi xây dựng X, và thường được thực hiện bởi một khuôn khổ DI hoặc chỉ ở một nơi trong một nhà máy viết tay.

Một số liên kết để biết thêm thông tin:

+0

> Khi bạn sử dụng tiêm phụ thuộc theo mọi cách, > thì bạn sẽ không cần truyền nhiều thông số cho các đối tượng. Tôi chưa bao giờ xem xét thực hiện DI cho tất cả các lớp học. Tôi chỉ muốn làm DI cho các lớp có sử dụng các công cụ bên ngoài, như dịch vụ web, cơ sở dữ liệu, có lẽ là cấu hình. Nếu tôi hiểu bạn đúng, bạn sẽ không bao giờ gọi giải quyết hay mới về bất cứ điều gì ngoài các lớp khung công tác? Cảm ơn câu trả lời của bạn :-) – Karsten

+0

Đến để nghĩ về một điều khác. Nó có nghĩa là tất cả các vật thể được tạo ra phía trước, một thời gian dài trước khi chúng thực sự có thể cần thiết, có lẽ chúng thậm chí không cần thiết chút nào? – Karsten

+0

Khi sử dụng DI tất cả các cách, bạn khởi động ứng dụng bằng cách lấy đối tượng gốc của ứng dụng từ vùng chứa DI, và sau đó bạn không còn truy cập trực tiếp vào vùng chứa. http://docs.google.com/Doc?id=dd2fhx4z_5df5hw8#xefn Các đối tượng sẽ được tạo khi một số đối tượng có chúng dưới dạng phụ thuộc được tạo. Nói chung, tất cả các đối tượng có cùng phạm vi vòng đời được khởi tạo cùng một lúc. Nếu một số đối tượng có phạm vi vòng đời khác nhau, thì bạn có thể tiêm một nhà máy để khởi tạo chúng vào đúng thời điểm. –

1

Tôi thường cho phép các cuộc gọi đến giải quyết phụ thuộc từ container ở những nơi như chính mặc dù tôi vẫn cố gắng giữ chúng vào một tối thiểu. Những gì tôi làm sau đó là cấu hình container trong một phương thức khởi tạo của một lớp thử nghiệm. Tôi có nó khởi tạo với việc triển khai giả cho bất kỳ lớp thử nghiệm nào cần gọi cho vùng chứa.

Các lớp kiểm tra không gọi bất cứ thứ gì yêu cầu vùng chứa được khởi tạo sau đó có thể bỏ qua nó và không sử dụng hàng giả. Tôi thường sử dụng mocks trong những trường hợp đó.

Tôi cũng sử dụng Microsoft Service Locator để phụ thuộc mà tôi đang thực hiện là trên thứ gì đó từ .NET Framework thay vì trên một vùng chứa cụ thể. Điều này cho phép tôi xuống đường sử dụng bất cứ điều gì tôi muốn ngay cả một container nhà ủ.

+0

Tôi vẫn muốn thấy một mô hình tốt đẹp về cách giải quyết điều này mà không tạo sự phụ thuộc vào lớp Chương trình ... –

+0

> Tôi giữ các cuộc gọi như vậy .. Bạn có nghĩa là cuộc gọi 'giải quyết' đối với vùng chứa ? – Karsten

+0

Có, tôi có nghĩa là các cuộc gọi 'giải quyết' đối với vùng chứa. –

0

Bạn có thể sử dụng lớp tĩnh làm bộ khởi tạo cho vùng chứa của mình. Một cái gì đó giống như BootStrapper.cs sẽ ổn. Sau đó bạn có thể tham khảo các phương thức lớp trong cả mã và các kiểm tra của bạn.

0

Vâng những gì bạn đang làm kỹ thuật là một vị trí dịch vụ trong lớp học của bạn.

Tôi nhớ đọc bài viết này một khi trở lại:

http://martinfowler.com/articles/injection.html

Đối với các lớp học của tôi, tôi không bao giờ cố gắng sử dụng Giải quyết trong đó. Tôi tạo ra các đối tượng thông qua các container khi tôi cần chúng. Đối với thử nghiệm đơn vị, tôi hoặc sử dụng một số thư viện giả và các lớp sơ khai.

0

Vấn đề nằm ở chỗ thực tế là bạn đang cố gắng thử nghiệm phương pháp chính. Phương pháp này hầu như không thể kiểm tra đơn vị.

tôi cho rằng tốt nhất là không để đơn vị kiểm tra phương thức Main của bạn bởi vì:

  • Sự nhấn mạnh của đơn vị kiểm nghiệm hiện đại là về thiết kế
  • Bạn nên hạn chế tối đa sự phụ thuộc vào cấu hình trong các thử nghiệm đơn vị. Cấu hình có thể được kiểm tra bằng thử nghiệm khói hoặc tích hợp.
+0

Không, tôi không thử kiểm tra phương pháp chính. – Karsten

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