Kiedy @Mock, a kiedy @Autowired w JUnit

1

J/w, przerabiam sobie jakieś tam przykładowe testy jednostkowe z kursu na Udemy i raz gościu używa @Mock, raz @Autowired. Istnieje jakaś wskazówka kiedy używać jednej adnotacji, a kiedy drugiej ? Wiem jaka jest różnica w działaniu między jedną a drugą, ale jest jakaś zasada, że np do repozytoriów dajemy @Autowired czy od czego innego to zależy ?

2

Skoro zadajesz takie pytanie to na 100% nie rozumiesz jaka jest różnica i co te adnotacje oznaczają. Ja generalnie zalecam w ogóle nie wstrzykiwać przez pola tylko przez konstruktor i nagle ten problem w ogóle znika.

2

Koledze chodzi chyba bardziej, że w testach widzi te dwa typy adnotacji i nie wie o co chodzi :D

Adnotacja @Mock to adnotacja biblioteki Mockito. Powoduje ona, że pole nią oznaczone będzie zawierało mock stworzony przez Mockito.
Do działania wymaga @RunWith(MockitoJUnitRunner.class) lub wywołania MockitoAnnotations.initMocks(this);

Adnotacja @Autowired to adnotacja Spring Framework. Powoduje, że pole nią oznaczone będzie zawierało obiekt danego typu wstrzyknięty z kontekstu Springa.
Do działania wymaga @RunWith(SpringRunner.class).
Czyli to działa tylko w przypadku testów integracyjnych, gdzie mamy cały kontekst Springa postawiony.

Przykład w Spring Boot i Spring Data:
Testujesz klasę UsersService, która potrzebuje UsersRepository do działania.

Gdy w teście wykorzystasz @Mock to repozytorium będzie mockiem i będziesz musiał / mógł zaprogramować jego zachowanie. Test nie wymaga innych klas i kontekstu Springa, czyli jest jednostkowy.

Gdy w teście wykorzystasz @Autowired to repozytorium będzie prawdziwym repozytorium do bazy lub do testowej bazy w pamięci H2 (zależnie co tam w kontekście Springa sobie ustawiłeś). Takie test jest raczej testem integracyjnym.

Zalecenia:

  1. Zgodnie z piramidą testów preferujemy testy jednostkowe, są szybkie i bardziej niezależne od różnych magii frameworków / środowisk.
  2. W przypadku jednak Repozytoriów mockowanie ma mały sens, bo tak naprawdę piszesz testy dla Mockito. Repozytoria testujemy integracyjnie

Ciekawostka na forum mamy takich userów: @mock i @Autowired

0

Dzięki. A kiedy używamy @Autowired nad jakimś repozytorium to możemy wtedy używać metody when()thenReturn() ? Pozmieniałem trochę w kodzie, żeby pole pod @Autowired nie było nullem i dostałem error Misplaced or misused argument matcher detected here, akurat w linijce z tą metodą.

1

Adnotacja @Mock to adnotacja biblioteki Mockito. Powoduje ona, że pole nią oznaczone będzie zawierało mock stworzony przez Mockito.

Bzdura. Inne biblioteki, jak EasyMock, także wspierają taką adnotacje.

Gdy w teście wykorzystasz @Autowired to repozytorium będzie prawdziwym repozytorium do bazy lub do testowej bazy w pamięci H2 (zależnie co tam w kontekście Springa sobie ustawiłeś). Takie test jest raczej testem integracyjnym.

Tylko o ile skonfigurujesz jakiś testowy kontekst. Inaczej guzik się tam wstrzyknie.

Zgodnie z piramidą testów preferujemy testy jednostkowe, są szybkie i bardziej niezależne od różnych magii frameworków / środowisk.

To żart? Testy integracyjne są równie ważne jak jednostkowe. Jest ich mniej, z definicji, ale ich brak to spory błąd. Tak tu tylko zostawie:

Teraz tak zupełnie serio:

  1. @Inject a nie @Autowired!
  2. Wstrzykiwanie przez konstruktor a nie przez pola! Wtedy problem w ogóle znika bo nie trzeba cudować z dodatkowymi adnotacjami ani specjalnymi runnerami dla testów. Tworzysz obiekt i musisz mu podać argumenty. Jak podasz realne obiekty to będą realne obiekty, jak mocki to będą mocki. Jeśli ktoś uważa że jest inaczej, to zalecam spróbować sobie wstrzyknąć do testowanego beana kilka stubów zaimplementowanych "ręcznie" zamiast konfigurowalnych mocków oraz kilka realnych obiektów. Przy field injection trudno to wykonać.
0

Ponawiam pytanie, czy metoda when() jest tylko dla mocków ?

1

Tak.

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