Spock jest frameworkiem do testów, którego popularność w świecie JVM-a jest nie do podważenia.
W internecie można znaleźć wiele tutoriali, które wprowadzają w podstawy adnotacji @Unroll
. Ogólnie chodzi w niej o to, że mamy możliwość uruchomienia tego samego kodu z wieloma zestawami danych. Najprostszy przykład użycia @Unroll
wygląda tak:
Interesowało mnie, ile jeszcze można wycisnąć z tej adnotacji, i o tym będzie ten post.
Wymagania
Przy pisaniu procesorów, które tworzą encje takie, jakie Localization, potrzebowałem przetestować sytuację, gdy do procesora wchodzi encja reprezentująca stronę z Memory Alpha, posiadająca jakiś zestaw kategorii. Na podstawie obecności tych kategorii były ustawiane konkretne booleanowe flagi w encji wyjściowej, w tym przypadku właśnie Localization. Gdybym chciał to zapisać w kilkunastu czy kilkudziesięciu testach, powtórzyłbym bardzo dużo kodu.
Jednocześnie chciałem sprawdzić w każdej iteracji więcej, niż jedną daną wyjściową, ponieważ obok flagi, która w sytuacji obecności danej kategorii miała być ustawiona na prawdę, chciałem też sprawdzać liczbę nienullowych pól w całej encji wyjściowej.
Trzecim wymaganiem było, by nazwa flagi była przechowywana jako string. To także okazało się możliwe z @Unrollem
. Chociaż zapewne to głównie zasługa Grooviego, który pozwala na dostęp do obiektów z użyciem tej samej składni, która umożliwia dostęp do map.
Ostatnim wymaganiem było, by zapisać w metodzie testowej interakcje, najlepiej z wyspecyfikowaną ich ilością. To też się prawie udało.
Implementacja
Ostateczna implementacja wygląda tam:
Opis implemenacji
W bloku given
zostały zapisane wszystkie wymagane w każdej iteracji interakcje. Można by też po prostu dostarczyć do metody testowej już zaprogramowane stuby, które miałyby te same interakcje.
W bloku expect
pobieramy lokalizację z procesora, a następnie, z użyciem nazwy flagi, którą też mamy w datasecie, porównujemy wartość flagi z kolejną wartością zapisaną w datasecie. Ostatecznie refleksją sprawdzamy ilość nienullowych pól w encji reprezentującej lokalizację.
W bloku where
znajdują się dane. Tutaj największą niespodzianką jest to, że można w ramach bloków konstruować obiekty i odwoływać się o innych metod. Patrząc na przykłady w sieci, nie jest to wcale oczywiste.
Ograniczenia
Nie znalazłem sposobu, by wyspecyfikować ilość interakcji w ramach jednej metody testowej z @Unrollem
. Interakcji nie można umieszczać w blokach given
i expect
, a z kolei blok then
nie może współegzystować z blokiem expect
. Jeśli więc chcemy sobie zaprogramować interakcje, możemy to zrobić tylko w bloku given
, ale bez zapisywania przy nich ilości.
Podsumowanie
Umiejętnie użyty @Unroll
pozwala napisać dowolny test, z wyjątkiem takiego, który zlicza ilość interakcji.
Kiedy używać @Unrolla
, a kiedy jest on overkillem? Myślę, że dobrą granicą są cztery bardzo podobne metody testowe. Jeśli tyle mamy, należałoby je połączyć w jedną metodą z @Unrollem
. Ale zgodnie z duchem reguły DRY, nawet 2 podobne metody testowe to nie byłoby za dużo, by zacząć używać @Unrolla
.
A co, jeśli mimo wszystko chcemy zliczać interakcje i mieć data tables? Moje doświadczenie pokazuje, że lepiej rozdzielać kod, który głównie operuje na interakcjach z zależnościami, od kodu, który głównie operuje na danych. Jeśli powstaną dwie osobne klasy, albo przynajmniej dwie osobne publiczne metody, z których jedna operuje głównie na zależnościach klasy, a druga głównie przetwarza dane, problem z brakiem zliczania interakcji przy użyciu @Unrolla
powinien zostać zminimalizowany.