Czy wstrzykiwanie zależności jest niezbędne do testów jednostkowych?

55

Czy stosowanie wstrzykiwania zależności (DI) jest niezbędne do testowania jednostkowego?

Nie mogę wymyślić innej alternatywy dla izolowania kodu, aby można go było przetestować. Ponadto wszystkie przykłady, które widziałem, wykorzystują ten wzór. Czy to dlatego, że jest to jedyna realna opcja, czy istnieją inne alternatywy?

Tom Squires
źródło
5
Wstrzykiwanie zależności nie jest niezbędne, ale szersza koncepcja odwrócenia kontroli jest.
Jeremy Heiler
Tutaj jest coś do powiedzenia na temat skali. Jeśli mam małą bazę kodu z bardzo małą liczbą warstw, DI może nie być przydatne.
JB King
@JBKing, jeśli masz małą bazę kodu, nie potrzebujesz warstw ani testów jednostkowych
Sklivvz
1
Wiele decyzji projektowych jest potrzebnych do przetestowania kodu. Zacznij pisać testy i dowiedz się.
Nathan Cooper

Odpowiedzi:

42

DI znacznie ułatwia testowanie jednostek. Ale nadal możesz pisać testy jednostkowe bez DI. Wiele testów jednostkowych zostało napisanych już przed rozpowszechnieniem DI. (Oczywiście niektóre z tych używanych technik są identyczne lub bardzo podobne do DI, nie wiedząc, że ma fantazyjną nazwę :-)

Sam często korzystałem np. Z interfejsów i fabryk zanim poznałem DI. Rzeczywista nazwa klasy fabrycznej mogła zostać odczytana z pliku konfiguracyjnego lub przekazana do SUT jako argument.

Innym podejściem jest wykorzystanie singletonów (lub ogólnie dostępnych danych w ogólności). Tak, wiem, że ogólnie nie jest to zalecane przez wielu (w tym przeze mnie). Mimo to może być wykonalne w określonych sytuacjach, szczególnie jeśli singleton zawiera statyczne dane konfiguracyjne, które nie są specyficzne dla przypadków testowych, ale różnią się między środowiskiem produkcyjnym i testowym. Oczywiście ma swoje znane problemy, więc DI jest lepszy, jeśli możesz go użyć. Ale często (np. W starszych systemach) nie możesz.

Mówiąc o tym, Efektywna praca ze starszym kodem opisuje wiele sztuczek, aby uzyskać dostęp do starszego kodu objętego testami. Wiele z nich nie jest fajnych i nie ma na celu rozwiązania długoterminowego. Umożliwiają one jednak utworzenie pierwszych cennych testów jednostkowych dla systemu, który w przeciwnym razie byłby niestabilny ... co pozwala na rozpoczęcie refaktoryzacji i ostatecznie (między innymi) wprowadzenie DI.

Péter Török
źródło
Uzgodniony, DI jest szczególnie przydatny do kpienia z obiektów. Ale istnieje wiele scenariuszy, w których DI jest bezużyteczny w testach.
Kemoda
@Kemoda jak na przykład co?
BЈовић
@VJovic Na przykład samodzielne obiekty. Myślę o metodzie, która przyjmuje pewne argumenty i wykonuje pewne rzeczy, ale nie zależy od innego komponentu (a zatem nie ma potrzeby DI).
Kemoda
@Kemoda Wygląda na to, że opisujesz programowanie funkcjonalne i używasz DI. Wstrzykujesz swoje zależności jako parametry metody.
Erik Dietrich
3
@huggie, dlaczego wyciekłyby tutaj szczegóły implementacji? Wstrzykiwana zależność jest zwykle ukryta za interfejsem, a cała sprawa polega na tym, że klasa klienta nie ma pojęcia - i nie jest zainteresowana - czy faktyczna implementacja tej zależności jest prawdziwą klasą produkcyjną czy próbą. Jego tworzenie odbywa się poza klasą klienta, można zobaczyć tylko gotową instancję.
Péter Török,
56

Oddzielenie jest niezbędne do testów jednostkowych. DI to świetny sposób na osiągnięcie oddzielenia.

nlawalker
źródło
17
Bardzo prawdziwe stwierdzenie, które w żaden sposób nie odpowiada na pytanie.
Travis,
10

W zależności od używanych technologii możesz izolować zależności bez korzystania z DI. Na przykład w świecie .NET Moles pozwala izolować zależności bez wzorca DI.

To powiedziawszy, uważam, że te ramy izolacyjne są napisane i przeznaczone do sytuacji w twoim kodzie z zewnętrznymi zależnościami (system plików, baza danych itp.). To, że można to zrobić, nie oznacza, że ​​powinien.

Wstrzykiwanie zależności umożliwia testowanie jednostkowe, ale także modyfikację zachowania obiektu bez zmiany kodu tego obiektu (zasada otwarcia / zamknięcia). Tak więc nie jest to tylko testowalny kod, ale wynikający z niego elastyczny kod. Ogólnie stwierdziłem, że istnieje silna korelacja między kodem możliwym do utrzymania / elastycznym a kodem testowalnym.

Erik Dietrich
źródło
3
Lub Moles pozwala ci myśleć, że masz czysty, dobrze skonstruowany, sprawdzalny kod, ponieważ testujesz za pomocą magii.
Wyatt Barnett
@WyattBarnett Tak, bardzo prawdziwe. Moles ma zdolność wywoływania skrzywienia, aby ktoś powiedział „kto w ogóle potrzebuje tego całego polimorfizmu i rzeczy otwartych / zamkniętych ?!?”
Erik Dietrich
1
Mole zostały zastąpione przez podróbki , a ze strony podróbek „Framework Fakes pomaga programistom tworzyć, utrzymywać i wprowadzać fałszywe implementacje w testach jednostkowych”.
Podpisz
1
@Sign Twój link mówi również: „Framework Fakes może być używany do shimowania dowolnej metody .NET, w tym nie-wirtualnych i statycznych metod w zapieczętowanych typach.”. Fakt, że szkielety izolacyjne mogą być używane w połączeniu z DI nie oznacza, że są to DI.
Erik Dietrich
4

Nie, DI nie jest niezbędny do testów jednostkowych, ale bardzo pomaga.

Możesz używać fabryk lub lokalizatorów i testować tak samo, jak w przypadku DI (po prostu nie tak elegancki i wymagałby większej konfiguracji).

Ponadto obiekty próbne byłyby ważne w starszych systemach, w których wiele wywołań jest delegowanych do funkcji zamiast zależności. (Obiekty próbne mogą być również szeroko wykorzystywane w odpowiedniej konfiguracji)

Mogą istnieć konfiguracje, w których testowanie jest prawie niemożliwe. Nie zależy to jednak od tego, czy stosuje się wstrzykiwanie zależności.

smp7d
źródło
3

Nie , wstrzykiwanie zależności nie jest niezbędne do testów jednostkowych.

Wstrzykiwanie zależności pomaga, jeśli masz klasę, która potrzebuje zależnej instancji klasy, aby wykonać pewne przetwarzanie podrzędne. Zamiast DI można rozdzielić logikę metody biznesowej na część gromadzącą dane (która nie może być testowana jednostkowo) i część obliczeniową, którą można przetestować jednostkowo.

Przykład (przy użyciu DI) Ta implementacja zależy od pracownika, konta, ...

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

Po oddzieleniu gromadzenia danych i obliczeń:

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

Część obliczeniową można łatwo przetestować bez wstrzykiwania zależności.

k3b
źródło
1
  • Wstrzykiwanie zależności nie jest niezbędne do testów jednostkowych

  • Z drugiej strony odwrócenie kontroli jest niezbędne, gdy chcesz zamienić jedną implementację na inną.

CodeART
źródło
0

Tak, istnieją alternatywy dla zastosowania DI do izolacji.

Jedną z możliwości jest użycie fabryk lub ServiceLocator, które można skonfigurować na podstawie testów, aby zwracały fałszywe obiekty zamiast rzeczywistych.

Innym jest użycie odpowiedniego szkieletu izolacyjnego lub narzędzia kpiącego. Takie narzędzia istnieją dla niemal każdego nowoczesnego języka programowania (przynajmniej dla Java, C #, Ruby i Python). Mogą izolować testowaną klasę od implementacji innych klas / typów, nawet jeśli testowana klasa bezpośrednio tworzy swoje zależności.

Rogério
źródło