Słowo wstępu
Jednym z ciekawszych etapów wytwarzania oprogramowania jest… testowanie (o ile możemy mówić o etapach, bo w dzisiejszym świecie raczej mówi się o fazach, które przebiegają w miarę równolegle w ramach wytwarzania nowych funkcjonalności). Testy nie przebiegają w próżni, wymagają środowisk testowych odpowiednio uzbrojonych w konfigurację i dane testowe.
Stosunkowo prosto jest testować pojedynczy system, lecz w typowym dużym przedsiębiorstwie pojedyncze odizolowane systemy występują niezmiernie rzadko. Część systemów jest na etapie utrzymania, część na etapie intensywnego rozwoju, a część dopiero jest wprowadzana do użytku.
Co charakteryzuje środowisko produkcyjne w typowym przedsiębiorstwie? Jest to kilka do kilkudziesięciu systemów zintegrowanych w jakiś sposób, przeważnie przez EAI, ESB, lub point-to-point, za pomocą WebServices, MQ, replikacji plikowej (tzw. batch integration) itp. Rozwojem tych systemów zajmują się różne jednostki przedsiębiorstwa i firm współpracujących.
Pudełek nigdy nie za dużo, ale trudno się żongluje
Ze względu na trudności w budowie architektury środowiska zintegrowanego o charakterystyce luźno powiązanych systemów (loose coupling), zmiana w jednym systemie pociąga konieczność wykonania zmiany w innym, jednocześnie dostosowując protokół komunikacyjny między nimi. Często kompromisy podejmowane podczas wytwarzania oprogramowania powodują, że pełna separacja to tylko teoria. Testy funkcjonalne w środowisku zintegrowanym, a jednocześnie silnie powiązanym stanowią wyzwanie dla każdej organizacji, a przeprowadzanie testów o charakterystyce integracyjnych w takim środowisku jest prawie niewykonalne.
Z punktu widzenia rozwoju systemów możemy wyróżnić następujące środowiska względem rodzaju przeprowadzanego testu/działalności:
DEV – Deweloperskie – Development Test
SYS – Testów systemowych – manualnych – System Test
ATE – Testów ciągłej integracji (lub testów automatycznych) – Automated Test
UAT – Testów akceptacyjnych – User Acceptance Test
PRE – Testów instalacji paczki i infrastruktury – Preproduction Test
EFF – Testów wydajnościowych – Efficency Test
DIS – Testów wypadkowych – Disaster Recovery & Failover Test
MIG – Testów migracji – Data Migration Test
UPG – Testów podniesienia wersji – Upgrade Test
EDU – Edukacyjne (Często potrzeba przeszkolenia użytkowników z działania nowego oprogramowania zanim trafi ono na produkcję. Takie środowisko wymaga często nawet większej dostępności niż środowisko UAT)
Vanilla – Z pudełka (W przypadku środowisk opartych na gotowym oprogramowaniu dostosowanym do potrzeb klienta, możemy mówić również o środowisku testowym tzw. Vanilla, czyli takim z pudełka bez żadnego dostosowania, ewentualnie z zestawem danych demonstracyjnych)
Utrzymywanie tak wielu środowisk jest niewygodne ze względu na koszty zarówno licencyjne jak i operacyjne. Chcąc być w zgodzie ze sztuką należałoby utrzymywać po dwa lub więcej kompletów środowisk. Jedno dla wsparcia systemu produkcyjnego i poprawek przygotowanych dla niego, a drugie lub więcej kompletów na potrzeby rozwoju oprogramowania i procesu dostarczania zmian.
Z powodów praktycznych często łączy się przeznaczenie i wykonywane testy w jednym środowisku i tak można zaproponować następujący zestaw środowisk wraz z ich przeznaczeniem:
I – DEV
DEV – Deweloperskie
MIG – Testów migracji
ATE – Testów automatycznych
II – ST
SYS – Testów systemowych
MIG – Testów migracji
ATE – Testów automatycznych
III – UAT
UAT – Testów akceptacyjnych
MIG – Testów migracji
UPG – Testów podniesienia wersji
EDU – Edukacyjne
IV – PRE
PRE – Testów instalacji
EFF – Testów wydajnościowych i obciążeniowych
MIG – Testów migracji
UPG – Testów podniesienia wersji
DIS – Testów wypadkowych
V – Vanilla (opcjonalnie)
Część testów można powtarzać i realizować na różnych środowiskach, zależy to od etapu i cyklu testowego. Środowiska od I-IV powinny być zduplikowane tak by świadczyć usługi na potrzeby wsparcia systemu produkcyjnego oraz rozwoju.
Główne czynności i trudności użytkowania środowisk testowych
Środowiska same sobą zarządzać nie potrafią. Automatyzacja pozwala w dużym stopniu odciążyć administratorów i zarządzających zmianą od powtarzających się czynności, ale w przypadku gdy wiele inicjatyw próbuje współdzielić środowiska lub pojawiają się pewne kłopoty, to interwencja ludzka jest czymś nieuniknionym.
Budowa i odświeżanie środowisk
Wyzwaniem jest spójność danych przy budowie testowego systemu zintegrowanego. Poszczególne systemy konstruowane są ze zrzutów z produkcyjnych baz danych, wykonywanych w różnym czasie. Dodatkowo wolumen danych środowiska produkcyjnego niejednokrotnie przewyższa ten możliwy do testów na środowisku testowym. Kłopotem jest wybranie lub przycięcie danych produkcyjnych do takiego stanu, by nie tracić przekroju wszelkich możliwych przypadków.
Odświeżanie jest czynnością pozwalającą na przywrócenie witalności środowiska ze względu na degradację danych – dane mogą być degradowane np. poprzez kod, który je niszczył. Na środowiskach testowych również produkuje się wiele danych śmieciowych, w trakcie wytwarzania oprogramowania zmienia się model danych itp. Po odświeżeniu koniecznym staje się przywrócenie konfiguracji testowej – zmiana haseł, adresów, ścieżek – gdyż przeważnie zostają nadpisane konfiguracją produkcyjną.
Kolejną trudnością jest po prostu liczba systemów do uwzględnienia, mogą to być liczby 2-3 cyfrowe.
Gdy budujemy system jako pakiet gotowy do użycia i dostępny dla każdego i każda wersja jest świeżą i gotową do pierwszego użycia, proces budowania kompletnego i działającego systemu z konfiguracją testową (czyli takiego środowiska vanilla) może zostać całkowicie zautomatyzowany przy użyciu Jenkinsa z konfiguracją dedykowanego buildu oraz automatycznego aplikowania zmian na bazę danych przy użyciu odpowiedniego reżimu budowy skryptów SQL lub narzędzi takich jak liquibase. W przypadku oprogramowania dedykowanego dla Linux możliwe jest zbudowanie aplikacji do pakietów, a następnie automatyczna budowa maszyny wirtualnej wraz z całym oprogramowaniem zainstalowanym z pakietów, która to maszyna wchodzi w skład środowiska testowego.
Kontrola zgodności wersji
Co i z czym będzie współdziałało? Gdy konstruujemy środowisko zintegrowane stworzone z szeregu systemów liczy się jakie dokładnie wersje aplikacji aktualnie ze sobą współpracują. W przypadku nowszych systemów, powszechnym staje się wersjonowanie interfejsów oraz logiki biznesowej, co może znacząco pomagać. Niestety dla wielu organizacji kłopotem jest nawet nadawanie kolejnym wydaniom aplikacji konkretnego numeru wersji, a co dopiero konstułowanie systemów z wewnętrznym wersjonowniem logiki i interfejsów.
W przypadku modułów systemu pisanych w języku JAVA i budowanych przy użyciu Apache Maven robotę robimy my sami wpisując wszystko w pom.xml. W przypadku systemu produkcyjnego rzadko istnieją takie możliwości – samemu, często ręcznie, trzeba zapisywać, jaka wersja aplikacji weszła na produkcję i jakie wersje systemów są ze sobą zgodne. Dlaczego to jest potrzebne? Musimy wiedzieć z jakich komponentów i w jakiej wersji zbudować środowisko do testów by było zgodne z produkcją.
Instalowanie i propagowanie zmian
Za propagowanie zmian zawsze odpowiedzialny jest człowiek. Zalecane jest by tak zautomatyzować proces, by zmiany same gdy zostaną odpowiednio sprawdzone instalowane były na środowisku w sposób automatyczny (autodeploy). W przypadku środowisk DEV, ST oraz ATE propagacja zmian może następować raz – dwa razy dziennie poprzez odpowiednią konfigurację buildu w systemie ciągłej integracji. Dla UAT oprogramownie może zostać podniesione do najnowszej wersji, jeżeli np. przejdzie wszystkie testy na środowisku ST. Do tego celu warto zaprząc narzędzie do bugtrackingu zintegrowane z systemem ciągłej integracji oraz kontroli wersji – by na bieżąco obserwować postęp testów konkretnego buildu oraz to czy zgłoszone błędy zostały poprawione.
Temat wiąże się ze sposobem wersjonowania kodu (tu odsyłam do poprzedniego artykułu o kuferku) oraz z zarządzaniem procesem testowania. Trudno wyobrazić sobie sytuację, gdzie na każde środowisko trafia inny zestaw poprawek, oraz że potem te poprawki w innej konfiguracji propagowane są na kolejne środowisko, potencjalnie generując inne błędy – to przypomina żonglowanie nie tylko pudełkami, ale i kulkami i kręglami jednocześnie – łatwo dostać w głowę.
Oprogramowanie przeznaczone do releasu produkcyjnego powinno znajdować się w dedykowanej gałęzi, a na środowiska propagowany powinien być za każdym razem komplet binariów wraz ze zmianami dotykającymi struktury i konfiguracji. Powinno ograniczać się wyciąganie i przenoszenie drobnych zmian i utrzymywanie osobnych gałęzi dla każdego ze środowisk testowych z osobna, jest to nieefektywne ze względu na błędy popełniane przy scalaniu kodu (mearge) oraz konieczność budowania i instalowania dedykowanych binariów.
Uaktualnianie
Cześć środowisk / komponentów potrzebuje uaktualnienia, o patche, o kolejne wersje itp. Te czynności muszą przechodzić ścieżkę zarządzania zmianą tak jak zmiany funkcjonalne w systemach. Podobnie zmiany infrastrukturalne również powinny być analizowane i przechodzić ścieżkę zdrowia przez środowiska testowe.
Kontrola dostępu do danych zastrzeżonych
Tu podejść jest kilka, ale na razie nie spotkałem się by gdziekolwiek stosowano coś innego niż… testowanie na danych produkcyjnych. Oczywiście są firmy zdolne wydać na projekty zamazywania (scramblingu) danych setki tysięcy dolarów, ale… po co? Dokładne wykonanie scramblingu wydaje się graniczyć z cudem, wprowadzi dodatkowe błędy i jeżeli nie będzie zrealizowane zgodnie z rozkładami danych na produkcji doprowadzi do całkowicie niemiarodajnych wyników testów wydajnościowych. Testowanie na danych wygenerowanych wydaje się być również podejrzane, z prostego powodu, że dane wygenerowane mogą nie odzwierciedlać rozkładu i charakterystyki danych produkcyjnych.
Zaślepianie
Dla pewnych systemów koszt poniesiony na przygotowanie zaślepek (tzw. mocków) usług w systemie, które nie podlegają modyfikacji, ale wykorzystywane są w testach, staje się opłacalny np. wielokrotnie niższy niż licencja na kolejne środowisko lub koszt jego wielokrotnej budowy i odświeżania. Sprawa jest trudna, bo emulowanie usług w sposób inteligentny, a co za tym idzie kompletny, jest na granicy implementacji pełnej funkcjonalności. W przypadku wdrażania tzw. middleware w organizacji warto zadbać o budowanie zaślepek równolegle do wytwarzania i rozwoju systemów.
W trakcie testów automatycznych lub testów integracyjnych na środowiskach DEV i manualnych ST, zaślepki pozwalają na przeprowadzenie testów i przejście do dalszych kroków procesów bez integracji z systemami zewnętrznymi.
Podsumowanie
W tym artykule miejsce znalazło kilka aspektów związanych z testami i środowiskami wspierającymi testy. Tekst zawiera sugestię na co należy zwracać uwagę podczas projektowania procesów w około zarządzania środowiskami testowymi odwołując się do przypadku przedsiębiorstwa posiadającego wiele systemów zintegrowanych w środowisku produkcyjnym. Pokazano minimalny zestaw środowisk wspierający rozwój i utrzymanie środowiska produkcyjnego. Na pewno nie jest to kompletne ujęcie tematu, dlatego liczę na komentarze jak sytuacja wygląda z Waszego doświadczenia w organizacjach, w których pracujecie.
Fajny artykuł!
Dodam tylko że szkoda iż nie wspomniałeś o ISTQB i standaryzacji w nazewnictwie oraz systematyce i rodzajach testów.
Niedawno miałem okazję zdawać ich (tzn. ISTQB) egzaminy do których przygotowywałem się z darmowych i ogólnodostępnych materiałów. Przyznam że bardzo dobrze jest to opracowane i polecam.
Generalnie w branży IT dobrze jest być na bieżąco z ITIL jeśli chodzi o współpracę biznes-IT (support, service itd), ISTQB jeśli chodzi o współpracę Software Development – QualityAssurance.
Nie wspomniałem o ISTQB i standaryzacji w nazewnictwie i systematyce, bo niestety nie posiadam ISTQB oraz certyfikacji ITIL. Tworzenie wspólnego języka i ram, które dają standaryzacje nie powinno się pomijać.
Doświadczenia w tym artykule wywodzą się z kilku lat pracy przy wytwarzaniu oprogramowania w dużych organizacjach i model w jakim te organizacje pracowały był stosunkowo zbliżony, chociaż ludzie mający pojęcie o ITILu i posiadający ISTQB byli w znaczącej mniejszości.
Postaram się uzupełnić wiedzę, przed napisaniem drugiej części :-)