Là tiêm phụ thuộc cần thiết cho thử nghiệm đơn vị?


55

Là sử dụng tiêm phụ thuộc (DI) cần thiết cho thử nghiệm đơn vị?

Tôi không thể nghĩ ra một cách khác để cô lập mã để nó có thể được kiểm tra. Ngoài ra, tất cả các ví dụ tôi từng thấy sử dụng mẫu này. Đó là bởi vì đó là lựa chọn khả thi duy nhất hoặc có những lựa chọn thay thế khác?


5
Dependency Injection không cần thiết, nhưng khái niệm rộng hơn về Inversion of Control là.
Jeremy Heiler

Có một cái gì đó để nói cho quy mô ở đây. Nếu tôi có một cơ sở mã nhỏ với rất ít lớp thì DI có thể không hữu ích.
JB King

@JBKing nếu bạn có một cơ sở mã nhỏ, bạn không cần kiểm tra lớp hoặc đơn vị
Sklivvz

1
Rất nhiều quyết định thiết kế là cần thiết để làm cho mã của bạn có thể kiểm tra được. Bắt đầu viết bài kiểm tra và tìm hiểu.
Nathan Cooper

Câu trả lời:


42

DI làm cho thử nghiệm đơn vị dễ dàng hơn nhiều. Nhưng bạn vẫn có thể viết bài kiểm tra đơn vị mà không cần DI. Rất nhiều bài kiểm tra đơn vị đã được viết trước khi DI trở nên phổ biến. (Tất nhiên, một số trong số các kỹ thuật được sử dụng này giống hệt hoặc rất giống với DI mà không biết nó có một cái tên lạ mắt :-)

Bản thân tôi đã sử dụng các giao diện và nhà máy rất nhiều trước khi tìm hiểu về DI. Tên lớp nhà máy thực tế có thể đã được đọc từ tệp cấu hình hoặc được chuyển đến SUT dưới dạng đối số.

Một cách tiếp cận khác là sử dụng singletons (hoặc dữ liệu có thể truy cập toàn cầu nói chung). Vâng, tôi biết nó không được khuyến khích bởi nhiều người (bao gồm cả bản thân tôi) nói chung. Tuy nhiên, nó thể khả thi trong các tình huống cụ thể, đặc biệt nếu singleton chứa dữ liệu cấu hình tĩnh không phải là trường hợp thử nghiệm cụ thể, nhưng khác nhau giữa môi trường sản xuất và thử nghiệm. Tất nhiên nó có vấn đề đã biết, vì vậy DI là ưu việt hơn nếu bạn có thể sử dụng nó. Nhưng thường (ví dụ: trong các hệ thống cũ) bạn không thể.

Nói về điều đó, Làm việc hiệu quả với Mã kế thừa mô tả rất nhiều thủ thuật để có được mã kế thừa được bao phủ bởi các bài kiểm tra. Nhiều trong số này không tốt và không có nghĩa là một giải pháp lâu dài. Nhưng họ cho phép bạn tạo các bài kiểm tra đơn vị có giá trị đầu tiên cho một hệ thống không thể kiểm chứng khác ... cho phép bạn bắt đầu tái cấu trúc, và cuối cùng (trong số những người khác) giới thiệu DI.


Đồng ý, DI đặc biệt hữu ích cho việc chế nhạo các đối tượng. Nhưng có nhiều kịch bản trong đó DI là vô dụng trong các bài kiểm tra.
Kemoda

@Kemoda thích gì chẳng hạn?
BЈовић

@VJovic Ví dụ các đối tượng độc lập. Tôi nghĩ về một phương thức lấy một số đối số và thực hiện một số nội dung nhưng không phụ thuộc vào thành phần khác (do đó không cần DI).
Kemoda

@Kemoda Nghe có vẻ như bạn đang mô tả lập trình chức năng và bạn đang sử dụng DI. Bạn đang tiêm phụ thuộc của bạn làm tham số phương thức.
Erik Dietrich

3
@huggie, tại sao chi tiết thực hiện sẽ bị rò rỉ ở đây? Sự phụ thuộc được đưa vào thường ẩn sau một giao diện, và toàn bộ vấn đề là lớp máy khách không có ý tưởng nào - và không quan tâm đến việc - việc triển khai thực tế của phụ thuộc này là lớp sản xuất thực hay giả. Khởi tạo của nó xảy ra bên ngoài lớp máy khách, nó chỉ được nhìn thấy thể hiện đã sẵn sàng.
Péter Török

56

Decoupling là cần thiết để thử nghiệm đơn vị. DI là một cách tuyệt vời để đạt được sự tách rời.


17
Một tuyên bố rất đúng mà không có cách nào trả lời câu hỏi.
Travis

10

Tùy thuộc vào các công nghệ bạn đang sử dụng, bạn có thể cách ly các phụ thuộc mà không cần sử dụng DI. Chẳng hạn, trong thế giới .NET, Moles cho phép bạn cách ly các phụ thuộc mà không cần mẫu DI.

Điều đó nói rằng, tôi tin rằng các khung cách ly này được viết và dành cho các tình huống trong mã của bạn với các phụ thuộc bên ngoài (hệ thống tệp, cơ sở dữ liệu, v.v.). Đó là, thực tế là người ta có thể làm điều này không có nghĩa là anh ta hoặc cô ta nên.

Việc tiêm phụ thuộc cho phép thử nghiệm đơn vị, nhưng nó cũng cho phép sửa đổi hành vi của một đối tượng mà không làm thay đổi mã của đối tượng đó (nguyên tắc mở / đóng). Vì vậy, nó không chỉ là mã có thể kiểm tra, mà là mã linh hoạt mà kết quả. Tôi thường thấy rằng có một mối tương quan nặng nề giữa mã có thể duy trì / linh hoạt và mã có thể kiểm tra được.


3
Hoặc Nốt ruồi cho phép bạn nghĩ rằng bạn đã có mã kiểm tra rõ ràng, được kiểm chứng bởi vì bạn đang thử nghiệm thông qua phép thuật.
Wyatt Barnett

@WyattBarnett Vâng, rất đúng. Nốt ruồi có một khả năng gây khó chịu để khiến ai đó nói "ai cần tất cả những thứ đa hình này và những thứ mở / đóng, dù sao?!?"
Erik Dietrich

1
Nốt ruồi đã được thay thế bằng hàng giả và từ trang giả mạo "Khung Fakes giúp các nhà phát triển tạo, duy trì và tiêm các triển khai giả trong các bài kiểm tra đơn vị của họ" Âm thanh như DI với tôi.

1
@Sign Liên kết của bạn cũng cho biết, "Khung Fakes có thể được sử dụng để bắt chước bất kỳ phương thức .NET nào, bao gồm các phương thức không ảo và tĩnh trong các loại được niêm phong." Việc các khung cách ly có thể được sử dụng cùng với DI không có nghĩa là chúng DI.
Erik Dietrich

4

Không, DI không cần thiết cho thử nghiệm đơn vị, nhưng nó giúp ích rất nhiều.

Bạn có thể sử dụng các nhà máy hoặc thiết bị định vị và kiểm tra như bạn muốn với DI (chỉ cần không thanh lịch và sẽ yêu cầu thiết lập nhiều hơn).

Ngoài ra, Mock Object sẽ rất quan trọng trong các hệ thống cũ, trong đó nhiều cuộc gọi được ủy quyền cho các chức năng thay vì phụ thuộc. (Đối tượng giả cũng có thể được sử dụng rộng rãi trong một thiết lập phù hợp)

Có thể có các thiết lập trong đó kiểm tra là gần như không thể. Nhưng điều này không dựa trên việc sử dụng tiêm phụ thuộc hay không.


3

Không , tiêm phụ thuộc là không cần thiết cho thử nghiệm đơn vị.

Việc tiêm phụ thuộc sẽ giúp nếu bạn có một lớp cần một thể hiện của lớp phụ thuộc để thực hiện một số xử lý phụ. Thay vì DI, bạn có thể tách logic của phương thức kinh doanh thành phần lấy dữ liệu (không phải là đơn vị kiểm tra được) và phần tính toán có thể được kiểm tra đơn vị.

Ví dụ (sử dụng DI) Việc triển khai này phụ thuộc vào Nhân viên, Tài khoản, ...

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     if (amount > 100 && employee.isStudent())
        return false;
     if (to.getOwner().getFamiliyName() == employee.getFamilyName() && ...
        return false; // cannot transfer money to himself;
     ...
 }

Sau khi thu thập dữ liệu và tính toán:

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     return hasPermissionToTransferMoney(employee.isStudent(), employee.getFamilyName(), to.getOwner().getFamilyName(), ...);
 }

 // the actual permission calculation
 static bool hasPermissionToTransferMoney(boolean isStudent, string employeeFamilyName, string receiverFamilyName, ...)
     if (amount > 100 && isStudent)
        return false;
     if (receiverFamilyName == employeeFamiliyName && ...
        return false; // cannot transfer money to himself
     ...
 }

Phần tính toán có thể được kiểm tra dễ dàng mà không cần tiêm phụ thuộc.


1
  • Tiêm phụ thuộc là không cần thiết để thử nghiệm đơn vị

  • Mặt khác, việc đảo ngược quyền kiểm soát là điều cần thiết khi bạn muốn trao đổi một triển khai này sang một thực thi khác.


0

Có, có những lựa chọn thay thế cho việc sử dụng DI để phân lập.

Một cách khác là sử dụng các nhà máy hoặc ServiceLocator có thể được cấu hình từ các thử nghiệm để trả về các đối tượng giả thay vì các đối tượng thực.

Một cách khác là sử dụng một khung cách ly phù hợp hoặc công cụ chế nhạo. Các công cụ như vậy tồn tại cho mọi ngôn ngữ lập trình hiện đại (ít nhất là cho Java, C #, Ruby và Python). Họ có thể cách ly một lớp đang được kiểm tra khỏi việc thực hiện các lớp / loại khác, ngay cả khi lớp được kiểm tra trực tiếp khởi tạo các phụ thuộc của nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.