Ostatnio w dyskusji o Spring Beans wyszła ciekawa dyskusja (choć przez niektórych uznana za trolling) o testowaniu i mockowaniu. Jestem zwolennikiem mockowania, ale jako że zdanie @jarekr000000 jest odmienne, to chciałbym je lepiej poznać i podyskutować o tym.
Na wstępie zapraszam @jarekr000000 @somekind @scibi92 jako uczestników tamtej rozmowy, ale offc, post każdego jest mile widziany. W dyskusji prosiłbym o poruszenie jedynie tematów testowania i mockowania, ale nie konkretnych frameworków, w szczególności spring ;).
Załóżmy że stosujemy IoC bez żadnego frameworka DI i mamy do przetestowania klasę A.
class A{
private final B b;
private final C c;
public A(B b, C c){/*przypisania*/}
public X doSomething(Y y);
}
Klasa ta ma jedną metodę i w niej za pomocą 2 innych obiektów tworzony jest z parametru y wynik x. Ja w tym podejściu zamockowałbym B i C, tak żeby do testów trafiła tylko logika y. Robiąc ten test zakładam że:
- JVM dla 2 + 2 będzie zawsze zwracała 4 i ogólnie działała tak jak to przewiduję.
- Biblioteka testów jest napisana bezbłędnie
- Biblioteka mocków jest napisana bezbłędnie
Dla mnie jest to idealny test jednostkowy, ponieważ zrobiłem minimum założeń bez których nie dałoby się napisać żadnych testów. Oczywiście te założenia mogą okazać się nieprawidłowe, ale wtedy problem jest globalny co do aplikacji i to tam trzeba go rozwiązać a nie w specyficznym teście.
Gdybym jednak przakazał tam prawdziwe instancje B i C to:
- Nie byłby to test jednostkowy ale integracyjny. Uważam że test jednostkowy testuje możliwie najmniejszą jednostkę, a za integracyjny uważam taki który testuje zestawienie już 2 jednostek. Wiem że potocznie integracyjny to czasem od webserwisu do bazy danych albo jeszcze zewnętrznego systemu, ale gdy zestawiasz 2 klasy to już masz 2 odrębne moduły.
- Test jest zależny tylko od testowanej klasy. Jeżeli B ma implementację B1 a zostanie ona zamieniona B2, który działa inaczej i w pewnym momencie zaczęłaby szwankować to mój test zacząłby się wywalać. Moim zdaniem jest nieprawidłowe działanie bo jeżeli nie działa X, to test X powinien się wywalić a nie test Y. Jeżeli B byłaby bardzo powszechną klasą i była zależnością 100 innych, to w przypadku jej awarii wywaliłoby się 101 testów zamiast jednego. Dla mnie jest to informacja że coś nie działa, a nie że klasa X nie działa.
Oczywiście można założyć że jest to dodatkowy test, ale moim zdaniem zamiast testować B w 100 klasach tak samo, lepiej napisać 10 dodatkowych testów do samego B żeby upewnić się że jest idealna skoro zależy od niej tak wiele.