Wady użycia mocków z mock-frameworków

Idzie sobie transakcja z banku. Trafia ona ci na moje biurko i muszę ją zwalidować. Biorę ci ja JSR-303 i przepuszczam ci ja transakcję przez tą zabawkę…

Rzecz w tym, że mam kilka własnych walidatorów, które korzystają z danych pobranych z bazy. Dane sa pobierane raz i zapisywane w takim pseudo cache, który potrafi odpowiedzieć na różne pytania dotyczące poszczególnych banków (czy mają włączone pewne usługi, czy są aktywne itp.). Zatem chcąc przetestować to rozwiązanie należało by użyć mocka. Na tapetę trafia zatem Mockito i koleżanka Whendy, która będzie udawała nam bazę danych.

// offtopic:
koleżanka Whendy zawdzięcza swoje imię temu, że konfigurując mocka używamy metod when i then.
// koniec offtopicu

Szyba konfiguracja i dla mniejszych testów śmiga. Przy okazji chciałem sprawdzić jak to zagra w przypadku większego testu. Nadal bez bazy danych, ale już odpalając wszytko na raz. Wziąłem zatem dyżurny zestaw 100k transakcji testowych. Napisałem prosty test „profilujący” pod kątem czasu, odpaliłem i OutOfMemmoryError się stos skończył. Nosz… na razie bez przekleństw. Zaparzyłem świeżą kawę i dawaj sprawdzamy. Plik wejściowy ~41MB co daje jakieś ~70MB w obiektach. Do dyspozycji jest 256MB RAM dla JVM w TestNg. Hm… szybko dopinam Dupaprofiler dla pamięci i widzę, że wykłada się przy około ~40K obiektów. Na Twittera idą bluzgi w temacie JSR-303. Pól dnia walki i co się okazało?

Każdy mock ma dodatkowe featury

Generalnie każdy mock tworzony przy pomocy frameworku ma kilka fajnych fearturów. Jednym z nich jest zbieranie informacji o wywołaniach, argumentach przekazanych do obiektu itp. Te dane zżerają pamięć w zastraszającym tempie. Skończyło się na pseudoimpelentacji interfejsu. Działa tak samo jak mock, ale nie zbiera informacji o wywołaniach. Jeżeli zatem w trakcie testów kończy ci się pamięć to sprawdź czy twoje mocki nie są zbyt zasobożerne.
Jeżeli tak jest to sprawdź czy potrzebujesz informacji o wywołaniach. Jeżeli nie to wystarczy zamiast mocków z frameworku napisać własną pseudo implementację. Jeżeli potrzebujecie jednak pewnych informacji to nie pozostaje nic innego jak dołożyć pamięci.

10 myśli na temat “Wady użycia mocków z mock-frameworków

  1. No nie do końca w tym przypadku, bo na kość trzeba czekać. Pamiętaj, że mówimy tu o testach a’la jednostkowych, a te robisz na swoim stanowisku pracy. Zatem dokładanie RAMu jest drogie.

  2. A czy nie jest tak, że potrzebowałeś stubów a nie mocków? Zdaje się, że zależało Ci wyłącznie na danych zwracanych a nie fakcie wywołania metody.

  3. Dużo zależy co rozumiemy przez stub, a co przez mock. Narzędzia do mockowania niestety nie dostarczają stubów, czyli takich nicnierobiących, blondynkowantych obiektów, które tylko leżą i pachną.

  4. Co masz na myśli pisząc że „nie dostarczają stubów”? To od programisty zależy jak wykorzysta danego test doubla. Jeżeli chcesz to mówisz mu tylko co ma zwrócić – i masz stuba. Jeżeli chcesz, weryfikujesz jakie jego metody wywołano – i już masz test-spy czy też mocka. Mówisz – masz. 🙂

  5. Trochę nieprecyzyjnie to ująłem. Stub to taki obiekt, który nie rejestruje informacji o wywołaniach, bo to robi mock, a niestety w Mockito nie udało mi się tego wyłączyć.

  6. hm, chyba dalej nie wiem w czym problem. Stub to coś co zwraca Ci wartości jakich pragniesz. Fakt że rejestruje również informacje o wywołaniach nie ma znaczenia, dopóki nie zweryfikujesz tychże wywołań.

    …cóż, mogę tylko zachęcić do lektury http://practicalunittesting.com (już niedługo na rynku!) gdzie takie rzeczy są wyjaśnione 🙂

  7. Zgoda, że z funkcjonalnego punktu nie ma to znaczenia, ale z praktycznego ma. Rejestrowanie wywołań zajmuje ogromne ilości pamięci. W moim przypadku doprowadziło to do przepełnienia i wywalało test.

  8. Może to wynikało z nieprawidłowego użycia biblioteki. Zamiast stworzyć taką pseudo implementację cache i skonfigurować ją na sztywno za pomocą kilku IFów użyłem Mockito. Tyle tylko, że odczytów z cache było set tysięcy, a każdy musiał zostać nagrany. To spowodowało wyprodukowanie wielu obiektów trzymających informację o poszczególnych wywołaniach i w konsekwencji koniec RAM.

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax