Czy łatwiej? Nie powiedziałbym. Jeżeli chciałbyś potraktować DB jako IO i zamiast mockowania, stworzyłbyś klasę symulującą DB, to musiałbyś zaimplementować wszystkie pozostałe metody zawarte w Repozytorium (zwracając nulla w sytuacji gdy nie chciałbyś implementować metody, mogłoby się źle skończyć).
Dużo prościej i bezpieczniej (według mnie) jest zmockować dane metody i zwrócić jakieś obiekty przygotowane w metodzie oadnotowanej @Before.
Problem pojawia się w chwili, gdy używa się JPQL,
JPQL czy inne rzeczy sobie przetestujesz integracyjnie, natomiast testując zachowania modułów/klas testujesz jednostkowo. Nie oszukujmy się, zaimplementowanie CRUDowego repozytorium/DAO to bardzo prosta sprawa i nie zajmuje wiele czasu, a wielokrotnie będziesz z tego korzystać.
Testowanie mapperów ... ostatnio jeden z użytkowników, wspomniał o tworzeniu własnych mapperów (wraz z upraszczaniem typów zmiennych np. zwykły String zamiast Enuma, czy String reprezentujący datę w odpowiednim formacie) i powiem, że spodobał mi się ten pomysł. Testować - nie zaszkodzi, a może kiedyś pomoże.
Na dodatek, to był tylko przykład. Tak samo jak drugi przykład który podałem z zapisywaniem jakiegoś obiektu w bazie danych za pomocą własnoręcznie napisanych transakcji . Tutaj też według mnie lepiej wziąć, rozbić to na trzy funkcje (otwarcie połączenia, zapisanie obiektu, zamknięcie połączenia).
Edit: Jeszcze jedno pytanie odnośnie walidacji. Czy poprawnym (przy np walidowaniu nazwy Usera) jest rzucenie wyjątkiem np IllegalArgumentException()?
Co do edita - to zależy. Od wielu czynników, np. jak masz mapowane wyjątki, tzn jak trafiają do usera czy tam generalnie poza moduł. IMHO można.
Generalnie po co testować mappery? Masz jakiś obiekt, następnie wołasz coś co zapisuje ci ten obiekt gdzie chcesz i potem sprawdzasz co się zapisało. Zakładałbym, że jeżeli np. korzystasz bezpośrednio z jakiegoś drivera do bazy danych czy tam spring data albo czegoś innego to ktoś inny to przetestował żeby pola nie zginęły po drodze, czyli jeżeli test się nie powiedzie to albo zepsuleś mapper albo nie potrafisz korzystać z narzędzi (np. ww drivera)
Albo w sytuacji gdybyśmy chcieli zapisać coś w bazie danych i rozbilibyśmy funkcję na openConnection(), persist(), closeConnection()?
Jak chcesz coś zapisać to wystaw sobie interfejs z jakąs zgrabną metodą save
. W testach jednostkowych dotykanie I/O i testowanie otwierania połączenia i takich detali jest moim zdaniem nie na miejscu. W testach jednostkowych chcesz przetestować zachowanie np. ktoś chce zarejestrować użytkownika. Efekt jest taki, że użytkownik zostaje zarejestrowany, gdzieś tam się zapisały jego dane. To w jaki sposób jest to robione pod spodem, czy to JPQL czy springowe repository, czy do postrgesa czy do mongo nie ma znaczenia. Nie ma co się betonować z technologią, nie o to chodzi
Pierwsze słyszę o stub in memory, co to jest?
public interface TeamRepository {
List<Team> findAll();
Team save(Team team);
}
class InMemoryTeamRepository implements TeamRepository {
private final Map<String, Team> storage = new HashMap<>();
@Override
public List<Team> findAll() {
return new ArrayList<>(storage.values());
}
@Override
public Team save(Team team) {
storage.put(team.toExistingTeam().getName(), team);
return team;
}
}
wtedy nie mockujesz danych testująć, tylko np masz test, gdzie testujesz powiedzmy zmiane adresu uzytkownika. To na poczatku takiego testu trzeba zalozyc, ze taki uzytkownik w ogole istnieje, wiec go zapisujesz, czyli normalnie po bozemu wkladasz do repo albo najlepiej przez cały moduł (jakas tam fasadę czy coś innego)