Niemalże sto sześćdziesiąt milionów aktywnych użytkowników korzysta z usługi Spotify, żeby słuchać ponad trzydziestu pięciu milionów dostępnych utworów. Niektórzy delektują się swoją ulubioną muzyką nawet przez kilka godzin dziennie. Jeżeli weźmiemy pod uwagę, że istnieją setki możliwych konfiguracji urządzeń, z których korzystają użytkownicy aplikacji, to nie ma czemu się dziwić, że jest wiele okazji, żeby usługa Spotify została sparaliżowana przez bugi.
Dlatego też warto jest przyjrzeć się temu, w jaki sposób przedsiębiorstwo przeciwdziała błędom mogącym uprzykrzyć życie osobom korzystającym z dostarczanego przez nie streamingu utworów muzycznych.
Spotify podczas wyszukiwania błędów wykorzystuje jednocześnie testy manualne i automatyczne. Testy manualne, mimo licznych wad takich jak powolność, czy możliwość popełnienia błędów, są nieodzownym elementem procesu i nie wydaje się, żeby miały w najbliższym czasie wyjść z powszechnego użytku. Automatyczne testy usprawniają dużą część pracy, dzięki czemu uwaga osób odpowiedzialnych za QA może zostać zwrócona na inne, wymagające wypróbowania aspekty aplikacji.
Cele testerów Spotify
Jakie cele stawiają sobie testerzy Spotify? Istnieją trzy fundamentalne zasady, które kierują procesem testowania software w firmie. Pierwszą z nich jest upewnienie się, że dany kod rzeczywiście robi to co powinien. Oczywiście przeprowadzanie testów, które służą tylko i wyłącznie sprawdzeniu tego czy program działa prawidłowo byłoby niewykorzystaniem pełni potencjału drzemiącego w QA.
Drugim celem jest pozyskanie feedbacku, na którym można będzie opierać się podczas dalszych prac. Feedback musi być pozyskany w sposób możliwie szybki, jednocześnie będąc na tyle pewnym, że można będzie w oparciu o niego tworzyć wnioski, które ułatwią zespołowi korektę projektu.
Trzecim celem QA Spotify jest zapewnienie tego, żeby utrzymanie powstałego kodu było możliwie proste. W wielu firmach testerzy nie poświęcają temu należytej uwagi, jednak Spotify zdecydowało się tutaj na pójście na przekór branżowym trendom.
Tradycyjna strategia przeprowadzania testów
Podstawą tradycyjnych strategii wyszukiwania błędów w software są testy jednostkowe. Polegają one na sprawdzaniu poprawności działania elementarnych części składowych kodu. Zaletą tego podejścia jest możliwości testowania powstającego kodu na bieżąco, dzięki czemu można wychwycić bugi, kiedy tylko się pojawią. Następuje w ten sposób redukcja czasu potrzebnego na znalezienie miejsca w kodzie, w którym wystąpił problem.
Ponadto testy jednostkowe mają tę zaletę, że dobrze poddają się automatyzacji.
Na wyższym stopniu skomplikowania są testy integracyjne. Metoda ta polega na grupowym testowaniu poszczególnych modułów wchodzących w skład software według planu. Istnieje wiele możliwych wariantów według, których mogą przebiegać testy integracyjne.
Microservices i zarzucenie tradycyjnego modelu testowania
Spotify zarzuciło powyższy, tradycyjny model testowania software z uwagi na przyjęcie odmiennej architektury aplikacji. Przedsiębiorstwo tworzy swoje oprogramowanie w systemie Microservices. Jest on dostosowany do potrzeb firm technologicznych, które świadczą swoje usługi milionom użytkowników korzystającym jednocześnie z różnorodnych urządzeń.
Częścią tej filozofii jest budowanie software w oparciu o działania autonomicznych zespołów programistów. We Spotify działa ponaddziewięćdziesiąt zespołów, w których pracuje ponad sześciuset pracowników IT.
Dzięki Microservices Spotfy może łatwiej skalować, testować oraz monitorować swoje oprogramowanie, a także posiadać kilka jego niezależnych wersji oraz w mniejszym stopniu ryzykować uszkodzenie systemu.
Strategia stosowana w Spotify
Jako, że nad oprogramowaniem pracuje kilka niezależnych zespołów, to najważniejszą częścią przeprowadzania testów stały się testy integracyjne. Dzięki nim trudności wynikające ze złego współdziałania ze sobą różnych modułów napisanych przez oddzielne zespoły są wyłapywane, a kod poddawany jest korekcie.
Testy jednostkowe grają w Spotify mniejszą rolę niż ma to miejsce w innych firmach IT. Ważnym dla zespołów testujących jest zapewnienie tego, żeby wyniki ich pracy były niezależne od środowiska, w którym przeprowadzane są testy oraz, żeby nachodzące na siebie systemy aplikacji nie ukryły przypadkiem jakiegoś bugu.
Przykład testu
Przyjrzyjmy się przykładowemu testowi podanemu przez oficjalny blog Spotify.
Testowana usługa polega na korzystaniu z bazy SQL w celu otrzymywania i zmieniania danych na życzenie klienta.
@BeforeClass
public static void setupClass() throws Exception {
startPostgresFromTestContainers();
seedDatabaseWithTestComponent();
startService();
}
@AfterClass
public static void tearDownClass() {
stopService();
stopPostgresFromTestContainers();
}
@Test
public void shouldReturnComponent() throws Exception {
final Request request = Request.forUri(„/components/testcomponent”);
final Response<ByteString> response = serviceHelper.serviceClient()
.send(request).toCompletableFuture().get();
assertThat(response.status(), is(OK));
final ComponentModel component = fromJson(
response.payload().get().utf8(), ComponentModel.class);
assertThat(component.component(), is(„testcomponent”));
assertThat(component.org(), is(„testorg”));
assertThat(component.repo(), is(„testrepo”));
}
Każdy test przeprowadzony w Spotify przebiega podobnie. Najpierw przygotowywana jest baza danych, potem odpalana jest usługa, a następne testowana jest dana funkcjonalność kodu. Dzięki tej metodzie najczęściej nie ma potrzeby wprowadzania żadnych większych zmian w formułach służących do testowania. Kolejną zaletą jest to, że samych testów nie przeprowadza się zbyt dużo, a te które mają miejsce są rzetelne i można polegać na ich wynikach.
Co prawda powyższa metoda z powodu swojej uniwersalności jest powolniejsza od istniejących alternatyw, ale możliwe dzięki niej jest zaoszczędzenie czasu na pisaniu oraz na modyfikowaniu testów, co ostatecznie stanowi większą wartość dla Spotify. Oszczędność czasu bierze się z tego, że metoda znajduje zastosowanie w różnorodnych sytuacjach, nawet tych wydawałoby się najbardziej skomplikowanych.
Przyjrzymy się sytuacji przedstawionej na poniższym diagramie. W danym fragmencie kodu występuje wiele możliwych do uzyskania wariantów. Napisanie oddzielnych testów dla wszystkich możliwości zajęłoby znaczą ilość czasu.
Zamiast tego programiści ze Spotify zdecydowali się zaadoptować posiadany już kod, tak żeby nadawał się on do wyszukiwania bugów w zaistniałej sytuacji. Oto on (wersja uproszczona):
@BeforeClass
public static void setupClass() throws Exception {
startPostgresFromTestContainers();
startPubsub();
startService();
mockMetadataService();
}
@AfterClass
public static void tearDownClass() {
stopService();
stopPostgresFromTestContainers();
stopPubsub();
}
@Test
public void shouldConsumeCommitBuildAndDeployEvents() throws Exception {
final PubsubTestMessage commitMessage = createTestMessage(
webhookFixtureCommitMessage,
webhookFixtureCommitAttributes);
publishMessage(commitMessage, githubEventTopic);
final PubsubTestMessage buildFinishedMessage = createTestMessage(
buildEventFixtureFinishedMessage,
buildEventFixtureFinishedAttributes);
publishMessage(buildFinishedMessage, buildEventTopic);
final PubsubTestMessage deploymentFinishedMessage = createTestMessage(
deployEventFixtureFinishedMessage,
deployEventFixtureFinishedAttributes);
publishMessage(deploymentFinishedMessage, deployEventTopic);
final Request request = Request.forUri(„/components/testcomponent/changes”);
final ApiResponseMatcher apiResponseMatcher = new ApiResponseMatcher(expectedApiFixture);
await().atMost(3, SECONDS).pollDelay(100, MILLISECONDS).until(
() -> serviceHelper.request(request).toCompletableFuture().get(),
apiResponseMatcher
);
}
Struktura kodu służącego do przeprowadzania testów pozostaje niezmieniona. Jest on każdorazowo adoptowany do radzenia sobie z nowymi problemami.
Wadą tej metody jest to, że w sytuacjach, kiedy wykaże ona błąd w kodzie, nie radzi sobie z podaniem przyczyny, która doprowadziła do zaistnienia danej sytuacji. Jedyną informacją, którą w takim wypadku generuje program jest to, że wyniki testów są sprzeczne z oczekiwaniami. Programiści muszą samodzielnie wyszukać przyczynę pojawienia się bugu.
Spotify stosuje standardowe testy jednostkowe w sporadycznych przypadkach, kiedy złożona część kodu jest oddzielona od reszty powstającego software.
Spotify zdecydowało się na wdrożenie metody testowania, której uniwersalność zapewnia możliwość wykluczenia wypadku pomyślnego przejścia przez testy wybrakowanego fragmentu kodu. Przedsiębiorstwo uzyskuje dzięki temu rezultaty testów, na których może polegać i które do tego generowane są wyjątkowo szybko. Zaoszczędzony w ten sposób czas przeznaczany jest na naprawianie błędów. Mimo sporej wady metody, którą jest trudność jednoznacznej identyfikacji przyczyny bugów, rachunek zysków i strat jest pozytywny. Firma oszczędza więcej zasobów dzięki stosowaniu uniwersalnego kodu do testów, niż traci w czasie dodatkowego wysiłku związanego z poszukiwaniem przyczyn błędów.
Kolejną zaletą szybkich, uniwersalnych testów, jest to że znacząco ułatwiają one utrzymywanie raz napisanego software. Podczas porządkowania kodu możliwe jest sprawdzenie wszystkich możliwych przypadków, na które wpływ mogła mieć modyfikacja wprowadzona przez zespół. Dzięki temu szansa, że software zostanie przypadkowo popsuty jest zminimalizowana.
Artykuł powstał dzięki:
Coders Lab
Łącząc doświadczenie edukacyjne ze znajomością rynku pracy IT, Coders Lab umożliwia szybkie i efektywne zdobycie pożądanych kompetencji związanych z nowymi technologiami. Skupia się się na przekazywaniu praktycznych umiejętności, które w pierwszej kolejności są przydatne u pracodawców.
Wszystkie kursy odbywają się na bazie autorskich materiałów, takich samych niezależnie od miejsca kursu. Dzięki dbałości o jakość kursów oraz uczestnictwie w programie Career Lab, 82% z absolwentów znajduje zatrudnienie w nowym zawodzie w ciągu 3 miesięcy od zakończenia kursu.
Zostaw komentarz