Чи необхідна ін'єкція залежності для одиничного тестування?


55

Чи важливе використання ін'єкцій залежностей (DI) для тестування одиниці?

Я не можу придумати іншу альтернативу виділення коду, щоб він міг бути перевірений. Також усі приклади, які я коли-небудь бачив, використовують цю схему. Це тому, що це єдиний життєздатний варіант чи є інші альтернативи?


5
Ін'єкційне введення не є суттєвим, але більш широкою є концепція інверсії управління.
Джеремі Хайлер

Тут є що сказати для масштабу. Якщо у мене невелика база коду з дуже малою кількістю шарів, то DI може бути не корисним.
JB King

@JBKing Якщо у вас невелика база коду, вам не потрібні шари або тестування одиниць
Sklivvz

1
Дуже багато дизайнерських рішень необхідні для того, щоб ваш код був перевіреним. Почніть писати тести і дізнайтеся.
Натан Купер

Відповіді:


42

DI полегшує тестування приладів набагато простіше. Але ви все одно можете писати одиничні тести без DI. Багато одиничних тестів було написано вже до того, як DI набув широкого поширення. (Звичайно, деякі з цих застосовуваних методів ідентичні або дуже схожі на DI, не знаючи, що вони мають фантазійну назву :-)

Я сам багато використовував, наприклад, інтерфейси та фабрики, перш ніж дізнатися про DI. Фактичне ім'я заводського класу, можливо, було прочитане з конфігураційного файлу або передано до SUT як аргумент.

Інший підхід - використання одиночних клавіш (або загальнодоступних даних загалом). Так, я знаю, що це взагалі не рекомендується багатьма (включаючи мене). Однак це може бути життєздатним у конкретних ситуаціях, особливо якщо одиночний містить статичні дані конфігурації, які не є специфічними для тестового випадку, але відрізняються між виробничим та тестовим середовищем. Звичайно, у нього є свої відомі проблеми, тому DI перевершує, якщо ви можете ним користуватися. Але часто (наприклад, у застарілих системах) ви не можете.

Якщо говорити про це, то, що ефективно працювати зі застарілим кодом, описується безліч хитрощів, щоб отримати застарілий код, охоплений тестами. Багато з них не є приємними і не розглядаються як довгострокове рішення. Але вони дозволяють створити перші цінні одиничні тести для інакше нестабільної системи ..., яка дає змогу почати рефакторинг, а згодом (серед інших) ввести DI.


Погоджено, DI особливо корисний для знущань над об'єктами. Але існує багато сценаріїв, коли DI є марним у тестах.
Kemoda

@Kemoda як наприклад, що?
BЈоviћ

@VJovic Наприклад автономні об'єкти. Я думаю про метод, який бере деякі аргументи і виконує деякі речі, але не залежить від іншого компонента (таким чином, немає необхідності в DI).
Kemoda

@Kemoda Це здається, що ви описуєте функціональне програмування, і ви використовуєте DI. Ви вводите свої залежності як параметри методу.
Ерік Дітріх

3
@huggie, чому б тут просочилися деталі щодо впровадження? Залежна залежність, як правило, прихована за інтерфейсом, і вся справа в тому, що клас клієнта не має уявлення про те, чи реальна реалізація цієї залежності є реальним виробничим класом чи знущанням над цим. Його екземпляр відбувається поза класом клієнта, він лише бачить готовий екземпляр.
Péter Török

56

Роз'єднання є важливим для тестування одиниць. DI - чудовий спосіб досягти роз’єднання.


17
Дуже правдиве твердження, яке жодним чином не відповідає на питання.
Тревіс

10

Залежно від технологій, які ви використовуєте, ви можете ізолювати залежності, не використовуючи DI. Наприклад, у світі .NET Moles дозволяє ізолювати залежності без шаблону DI.

При цьому я вважаю, що ці рамки ізоляції написані та призначені для ситуацій у вашому коді із зовнішніми залежностями (файлова система, база даних тощо). Тобто, те, що людина може це зробити, не означає, що він чи вона повинна.

Введення залежності залежить від тестування одиниць, але також дозволяє змінювати поведінку об'єкта без зміни коду цього об'єкта (принцип відкритого / закритого). Отже, це не просто перевіряється код, але і гнучкий код. Як правило, я встановив, що існує велика кореляція між підтримуваним / гнучким кодом та тестовим кодом.


3
Або Moles дозволяє вам думати, що у вас є чистий, добре врахований тестований код, тому що ви протестуєте магію.
Wyatt Barnett

@WyattBarnett Так, дуже правда. Мольс має здатність викликати вигоду, щоб змусити когось сказати "кому потрібен увесь цей поліморфізм та відкриті / закриті речі?"
Ерік Дітріх

1
Молів замінили підробками , і зі сторінки підробок "Рамка Fakes допомагає розробникам створювати, підтримувати та вводити манекенські реалізації у своїх одиничних тестах" Мені звучить як DI.
Увійти

1
@Sign Ваше посилання також говорить: "Рамка Fakes може бути використана для перенесення будь-якого методу .NET, у тому числі невіртуальних та статичних методів у запечатаних типах." Те, що рамки ізоляції можна використовувати спільно з DI, не означає, що вони є DI.
Ерік Дітріх

4

Ні, DI не є важливим для одиничного тестування, але він дуже допомагає.

Ви можете використовувати фабрики чи локатори та тестувати так, як це було б із DI (просто не настільки елегантно і вимагало б більше налаштувань).

Крім того, Mock Objects буде важливим у застарілих системах, де багато викликів делеговано функціям замість залежностей. (Макетні об’єкти також можуть широко використовуватися в належному налаштуванні)

Можуть бути налаштування, де тестування майже неможливо. Але це не ґрунтується на тому, використовується ін'єкція залежності чи ні.


3

Ні , введення залежності не є істотним для одиничного тестування.

Ін'єкція залежності допомагає, якщо у вас є клас, який потребує залежного екземпляра класу, щоб зробити деяку під-обробку. Замість DI ви можете розділити логіку бізнес-методу на частину отримання даних (яка не перевіряється одиницею) та частину обчислення, яка може бути перевірена одиницею.

Приклад (за допомогою DI) Ця реалізація залежить від співробітника, облікового запису, ...

 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;
     ...
 }

Після відокремлення збору даних та обчислення:

 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
     ...
 }

Розрахункову частину можна легко перевірити без введення залежності.


1
  • Введення залежності не є істотним для одиничного тестування

  • Інверсія управління з іншого боку є важливою, коли ви хочете поміняти одну реалізацію на іншу.


0

Так, існують альтернативи використанню ДІ для ізоляції.

Однією з альтернатив є використання фабрик або ServiceLocator, які можна налаштувати з тестів для повернення макетних об'єктів замість реальних.

Інша полягає у використанні підходящого ізоляційного каркаса або макетного інструменту. Такі інструменти існують практично для кожної сучасної мови програмування (як мінімум для Java, C #, Ruby та Python). Вони можуть ізолювати клас, який тестується, від реалізації інших класів / типів, навіть коли тестований клас безпосередньо підтверджує його залежності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.