Jak testujecie jednostkowo?

0

Cześć.
Mam taka zagwozdkę.

Kiedy piszę testy jednostkowe (praktykuję TDD)
To staram się zawsze używać instancji klasy, której testuję, przy pomocy operatora new.
Dzięki temu wiem np. że jeśli konstruktor ma dużo parametrów, to coś jest nie tak (pewnie klasa łamie zasadę SRP).

Tymczasem mój kolega dzisiaj pokazał mi test, w którym testował klasę, która ma 20 zależności, przekazywanych przez konstruktor. Użył adnotacji InjectMocks, bez wywoływania konstruktora.

Ja InjectMocks używam, jeśli mam mocki zależności w teście, a klasa testowana ma np. pola @Autowired
W innych sytuacja nie używam tylko przekazuje je w konstruktorze klasy testowanej.
Sposób z InjectMocks nie do końca do mnie przemawia, ale może to przyzwyczajenie...

Pytanie, jak wy testujecie jednostkowo?

6
  1. W ogóle nie wiąże pól przez @Inject / @Autowired tylko konstruktorem. Szczególnie że takie field injection sprytnie ukrywa cykliczne zależności przez wstrzykiwanie proxy i o tym że zrobiłeś coś takiego głupiego dowiesz się zwykle dużo później niż byś chciał
  2. Jeśli w ogóle pisze takie testy (tzn z jakiegoś powodu nie wystarcza mi porządny test integracyjny z fejkowymi endpointami/bazą in memory itd) to mockuje tylko to co koniecznie muszę, a reszta to prawdziwe obiekty, tak zeby faktycznie testować mój kod a nie mocki.

Zrób prosty test: wywal połowę kodu z klasy tego twojego kolegi. Jeśli testy nadal są zielone, to masz już odpowiedź ile są warte :)
A następnie zrób drugi test: zrób mały refaktor, zrób klasę która opakowuje kilka z tych 20 zalezności i znów puść testy. Teraz pewnie są czerwone, mimo że kod nadal działa poprawnie. Zastanów się teraz jaka jest w takim razie wartość takich testów.

5

Zależności ustawiam zawsze przez konstruktor nie korzystając z żadnej magii. Jeśli podstawiam testowe repozytorium/klienta in memory, to również tworzę własnego fejka. Mocków używam tylko w tym % przypadków, kiedy naprawdę zależy mi na weryfikacji interakcji i jej prametrów (często natomiast wystarcza test integracyjnym zamiast mocków). Da się i fajnie to działa. Polecam, Charles_Ray.

2

Podstawowe pytanie brzmi - co to za klasa z dwudziestoma zależnościami wstrzykiwanymi przez konstruktor i czy w ogóle da się ją przetestować?

5

Kolega uprawia #mocksturbację, prawie każdy to robi w pewnym momencie rozwoju.
A co do field injection:
http://olivergierke.de/2013/11/why-field-injection-is-evil/

3

Testujecie zapewne klasy by podnieść jakość kodu. W tym wypadku podniesie jakość kodu refactor klasy, która ma konstruktor na 20 argumentów.

4

20 zależności to jest objaw choroby zwanej Dependency Infection, zwanej inaczej Beanozą Zwyczajną. Leczenie objawowe - zwykle nieskuteczne na dłuższą metę - ciągle są nawroty, najlepiej całkiem odstawić Springa.

0

@jarekr000000:
Pracowałem z mikroserwisem gdzie encja (i tabelka w bazie) miały 100 pól, a serwis do niej wstrzykiwanych 30 zależności :D

Wiem, że generalnie wg sztywnych, dobrych praktyk encja nie powinna mieć więcej niż 3 pola, ale zrefaktoryzować taką 100polową encję to chyba nie lada wyzwanie ? Chociaż może problemem było niezastosowanie CQRSa w tym przypadku, bo faktycznie przy wyciąganiu tego front potrzebował bardzo sporo pól.

1

zrefaktoryzować taką 100polową encję to chyba nie lada wyzwanie

A ona się nagle taka stała? Często jest tak, ze jak ktoś od początku źle to napisał, to potem każdy woli dorzucić hacka zamiast naprawiać i taki potworek rośnie z upływem czasu.

przy wyciąganiu tego front potrzebował bardzo sporo pól

Nie widzę związku. To jak dużego DTOsa produkuje ci aplikacja żeby wysłać go na front, nie ma wiele wspólnego z liczbą zalezności w jakimś serwisie. Pola często można ładnie zgrupować, albo zrobić buildera który przejdzie przez kilka serwisów jak przez pipeline.

0

No nagle w ciągu 8 lat :D

Z tym dtosem dużym chodzi mi o to, że większość z tych pól była w niej tylko po to, bo front potrzebował dtosa. Do tego miała na sobie metody biznesowe, które korzystały z załóżmy 10 pól (a nie z 100). No po prostu klasa była reprezentacją tabelki w bazie + miała na sobie logikę. Myślę, że po prostu wystarczyło to co front czyta wywalić z encji i zwracać z jakiegoś query-serwisu albo zrobić widok zmaterializowany i w samej encji zostałoby o wiele mniej pól i tu już refraktor łatwiejszy.

2
Bambo napisał(a):

@jarekr000000:
Pracowałem z mikroserwisem gdzie encja (i tabelka w bazie) miały 100 pól, a serwis do niej wstrzykiwanych 30 zależności :D

Wiem, że generalnie wg sztywnych, dobrych praktyk encja nie powinna mieć więcej niż 3 pola, ale zrefaktoryzować taką 100polową encję to chyba nie lada wyzwanie ? Chociaż może problemem było niezastosowanie CQRSa w tym przypadku, bo faktycznie przy wyciąganiu tego front potrzebował bardzo sporo pól.

To jeden z głównych punktów mojej prezentacji z Devoxxa i Confitury - dlaczego Spring to patologia i dlaczego Beany to GOTO naszych czasów.

4

Ja bym w ogóle rozdzielił DTOsy które lecą na front / przychodzą z frontu od obiektów domenowych, bo inaczej wyjda ci wlaśnie takie kwiatki i klasyczne god object.

0

@jarekr000000: Muszę nadrobić, bo na chwilę obecną nie potrafię sobie wyobrazić jak Spring czy inny framework jest bezpośrednią przyczyną powstawania takich tworów. Przecież pisząc apkę bez żadnego frameworka, robiąc samemu DI przez 'new' też możemy doprowadzić do sytuacji gdzie wejście do modułu (czyli jakaś fasada) zawiera tysiące zależności.

Chyba, że chodzi Tobie o to, że pisząc to tak samemu w końcu sami zobaczymy, że jest coś nie tak, że dodajemy 10 czy 15 zależność, a w springu po prostu dodaje się pole + posiadając lomboka staje się to niezauważalne, a serwis puchnie :D

3
Bambo napisał(a):

Chyba, że chodzi Tobie o to, że pisząc to tak samemu w końcu sami zobaczymy, że jest coś nie tak, że dodajemy 10 czy 15 zależność, a w springu po prostu dodaje się pole + posiadając lomboka staje się to niezauważalne, a serwis puchnie :D

Dokładnie o to chodzi. Używając (jak ludzie) konstruktora ból już przy piątej zależności zaczyna być dokuczliwy. A takie klasy da się jeszcze tanio rozplątać.
(przy ponad 15-tu zależnościach rozlplątywanie to kanał).

1

@Bambo: można, ale musisz się więcej napocić, żeby tak zrobić i szybciej zauważysz że something is not yes

1 użytkowników online, w tym zalogowanych: 0, gości: 1