czwartek, 19 kwietnia 2012

Migracja z EasyMock’a na Mockito

Dostałem wczoraj w projekcie zadanie zmigrowania testów korzystających z EasyMock’a na Mockito. Zadanie to przypadło mi, ponieważ jakiś czas temu udało mi się wprowadzić do projektu Mockito, co uważam za duży sukces, gdyż jak wiadomo inicjowanie zmian w projektach nie jest łatwe.

Poniżej przedstawiam jak mi poszło.

9:00 Zbudowałem projekt, odpaliłem testy i zapisałem ile ich jest.
9:02 Sprawdziłem, że mam tylko 3 testy wykorzystujące EasyMock’a. W tym momencie stwierdziłem, że nie ma co szukać w Google jakiegoś migratora, ściągać, instalować i zastanawiać się, jak go uruchomić. Przy tak nie wielkiej liczbie klas do zmiany szkoda zachodu i lepiej zrobić to prymitywną metodą Search & Replace.
9:16 Skończyłem migrować 1wszą klasę.
9:19 Po przyjrzeniu się klasie zrobiłem jeszcze refaktoring, bo jak nie teraz to kiedy? Później nigdy nie nadejdzie.
9:20 Zacząłem modyfikować następną klasę.
9:27 Zakończyłem migrację i refaktoring. Wziąłem się za ostatnią klasę.
9:34 Ukończyłem modyfikacje dla 3ciej klasy.
9:35 Uruchomiłem wszystkie testy – działa.
9:41 Usunąłem wpisy dotyczące EasyMock’a w pom’ach Mavenowych. Tutaj przydała się funkcjonalność „Szukaj w plikach”, jaką daje Notepad++, abym mógł wyszukać wszystkie wpisy.
9:42 Odpaliłem builda i testy w Eclipse - zakończone sukcesem.
9:43 Odpaliłem builda i testy za pomocą konsoli – również zakończone sukcesem.
9:44 Rozpocząłem proces synchronizacji z repozytorium.
9:46 Zmiany zacomitowane.
9:52 Wystartował build na serwerze CI.
10:00 Build zakończył się jednym fail’ujacym testem. Dziwne, bo lokalnie działało. Jako że nie mam dostępu do konfiguracji Jenkinsa to i tak bym nie zidentyfikował problemu. Podszedłem do problemu pragmatycznie: usunąłem nadmiarowe wywołanie verify() i nieużywanego Mocka w jednym teście.
10:08 Rozpocząłem synchronizację z repozytorium.
10:11 Zmiany zacomitowane.
10:12 Wystartował kolejny build.
10:23 Build zakończony sukcesem, banan na ustach, można iść na herbatę.

Na całe szczęście mój obecny projekt jest jeszcze we wczesnej fazie wytwarzania, więc nie było dużo do roboty. Przy czymś większym, gdzie EasyMock jest namiętnie używany, łatwiej było by napisać jakiś skrypcik robiący brudną robotę za nas. Dodatkowo mój zespół ma niewielką wiedzę odnośnie używania mock’ów (i pisania dobrych testów), więc mam kogo ewangelizować :)

Poniżej jeszcze prezentuję przekształcenia z jakich korzystałem. Nie jest to oczywiście pełen zestaw, ale może on stanowić zajawkę Waszych migracji, albo może pomóc zrozumieć różnice między tymi bibliotekami.

import static org.easymock.EasyMock.createMock;
import static org.mockito.Mockito.mock;
createMock
mock
import static org.easymock.EasyMock.expect;
import static org.mockito.Mockito.when;
expect
when
andReturn
thenReturn
import static org.easymock.EasyMock.verify;
import static org.mockito.Mockito.verify;
Elementy do usunięcia:
import static org.easymock.EasyMock.replay;
replay

Do rozpatrzenia:
Przy wywołaniach verify() trzeba dopisać metodę z argumentami jaka powinna się wywołać. Albo jeszcze lepiej zastanowić się nad sensownością testu, gdyż często verify() jest zbędne. Ponadto anyTimes() zazwyczaj trzeba usunąć.

Na więcej problemów nie natrafiłem, ale zdaję sobie sprawę z tego, że przy większym systemie, gdzie EasyMock jest namiętnie wykorzystywany, może nie być tak łatwo. Przy okazji migracji można od razu wyłapać testy które są niedobrze napisane lub są niepoprawne z punktu widzenia Mockito, np. wywołanie verify() przed testowaną metodą.

3 komentarze:

  1. Ten komentarz został usunięty przez autora.

    OdpowiedzUsuń
  2. brawo Staszek! jak to mowil Gandhi - badz zmiana, ktora chcesz widziec na swiecie! Mnie bardziej interesuje jak dostales zielone swiatlo. Sama migracja to juz zabawa z komputerem gdzie ty rzadzisz. A co dzialo sie wczesniej?

    OdpowiedzUsuń
    Odpowiedzi
    1. @marcin
      Generalnie projekt od którego dołączyłem cierpiał (w sumie dalej jeszcze cierpi) na niedostatek testów.

      Jednym z moich pierwszych task'ów było dopisanie testów JUnitowych do logiki biznesowej. Wczesniej, jak rozmawiałem z pojedyńczymi osobami z zespołu, reklamowałem (czy też lansowałem) się jako obeznany w testach (w końcu robienie review książki o testach nie było na darmo). No i trochę cieżko mi było pisać z EasyMockiem (do tego starą wersją) i zapytałem, czy mógłbym dodać Mockito do projektu, bo to taki lepszy EasyMock. No i tak na probę miałem popisać kilka testów i później zaprezentować w zespole takie małe porównanie, aby pokazać co jest lepsze.

      Zaprosiłem na "prezentację" developerów z zespołu i głównego architekta. Na podstawie jednego testu pokazałem, ile trzeba napisać z EasyMockiem, a ile z Mockito, przy okazji ukazując wadę starej wersji EM, gdzie można było tylko interfejsy mockować. Pokazałem później na jednym sladzie obok siebie te dwa testy i czerwonym kolorem wykreśliłem to co jest zbędnę.

      Nastepnie zapytałem o ich odczucia. Wydaje mi się, że to było bardzo ważne, gdyż narzucanie swojego zdania w stylu Wujka Boba (piszcie testy, albo pójdziecie do piekła), mogło by tutaj nie zadziałać (gdyż nie mam jeszcze autorytetu w projekcie).

      Architekt i koledzy stwierdzili, że mniej kodu, to mniej możliwości popucia czegoś i że Mockito'we test się łatwiej czyta (aka Fluent interface) i można klasy mockować. Trochę tutaj oszukalem, ale wyszło na moje :)

      Później jeszcze jeden developer miał samemu sprawdzić, czy rzeczywiście Mockito jest bezproblemowe i czy się nadaje. No i się udało :)

      Jak chcesz u siebie w projekcie wprowadzic Mockito, to proponuję wybrać kilka "killer features" i najpierw osobno pogadać z kolegami (aby rozbudzić w nich chęć do zmiany), a póżniej po prostu zaprezentować. Myślę, że pomogło jeszcze parcie z góry na zwiekszenie pokrycia kodu, co z Mockito jest przyjemniejsze.

      Polecam prezntację Szczepana Fabra, która wisi gdzieś na jego blogu, gdzie tłumaczy motywację powstania Mockito. Mi ona pomogła się przygotować do pokazu możliwości tej biblioteki.

      Powodzenia we wprowadzaniu zmian.

      Usuń