testy jednostkowe

Jak przyspieszyć testy jednostkowe za pomocą Stub API

Jeśli kiedykolwiek mieliście okazję pracować z bazą kodu zawierającą więcej niż dziesięć klas, problemy związane z czasem wykonania Testów Jednostkowych są Wam zapewne dobrze znane. Choć ogólne działanie całego systemu musi i będzie się stopniowo poprawiać, w tym artykule spróbuję odpowiedzieć na pytanie, co my jako programiści możemy zrobić sami, żeby usprawnić swoją pracę.

Maciej Miłosz. Salesforce Engineering Cluster Lead w SoftServe. Ma ponad 7-letnie doświadczenie zawodowe. Od samego początku związany z technologią Salesforce. Uczestniczył w różnego rodzaju projektach – zarówno tych, które dostosowywały chmurę sprzedaży do potrzeb klienta, jak również w tworzeniu aplikacji ISV. Stara się rozwiązywać problemy i dostarczać rozwiązania, a nie kod. Gracz zespołowy z dobrymi umiejętnościami komunikacyjnymi.


Chcąc lepiej zrozumieć ten problem, posłużymy się przykładem. W tym celu utworzę metodę wywołaną w kontekście „before insert”, w triggerze podczas zapisu rekordu typu Contact. Jej głównym celem będzie ustawienie kilku pól w oparciu o nadrzędny rekord Account.

Test Jednostkowy

Zadaniem Testów Jednostkowych jest zagwarantowanie braku błędów w kodzie – poprzez sprawdzanie, czy części kodu działają bez problemów. W celu wdrożenia kodu w środowisku produkcyjnym, Testy Jednostkowe powinny objąć przynajmniej 75 procent kodu. Zazwyczaj proces tworzenia nowego Testu Jednostkowego jest dość prosty i składa się z następujących etapów:

  1. Tworzenia klasy testowej i/lub metody testowej.
  2. Tworzenia danych testowych.
  3. Wywoływania metody, którą chcemy przetestować.
  4. Oceny wyników.

Takie podejście dobrze się sprawdza w zarządzaniu małymi i średnimi projektami, ale może spowodować wiele problemów, gdy zwiększy się baza kodu. Standardowy Test Jednostkowy jest dość prosty w użyciu w następującym przykładzie:

Problemy z Testami Jednostkowymi

Każdy, kto stosuje w projekcie CI, dobrze wie, ile czasu potrzeba na wdrożenie produkcyjne. Czas wykonania wymagany w Testach Jednostkowych staje się problemem, zwłaszcza w przypadku większych zespołów – ze względu na duże wykorzystanie bazy danych.

W Salesforce tworzenie Testów Jednostkowych, które są faktycznie Testami Jednostkowymi, nie jest łatwe. W standardowym podejściu, zamiast Testów Jednostkowych, tworzone są Testy Systemowe. Ich głównym celem jest sprawdzenie ogólnej logiki, bez dzielenia kodu na wiele mniejszych części. W celu uzyskania faktycznych Testów Jednostkowych i skrócenia czasu wykonania testu, musimy zmienić sposób myślenia. Z testem w podanym przykładzie nie ma problemu, o ile test ten nie jest wykonywany na środowisku ze „154” deklaratywnymi narzędziami, które pracują z obiektem Contact.

Nowe podejście

Jeśli Test Jednostkowy ma zostać uznany za prawdziwy, musi zostać zbudowana warstwa dostępu do danych tylko do komunikowania się z bazą danych i zainicjowania nowego sposobu wykonywania testów – wszystko w pamięci. Pojawiają się przy tym następujące pytania:

  1. Jak zbudować dane testowe bez wykorzystania DML?
  2. Co, jeśli logika obejmuje SOQL?
  3. Jak ta dodatkowa warstwa wpłynie na pracę programistów oraz utrzymanie kodu?

Najważniejszym polem zapisu jest ID i jest to jeden z kluczowych powodów, dla których wykorzystujemy DML podczas konfiguracji testów. W budowaniu odpowiednich Testów Jednostkowych, baza danych nie jest wymagana do uzyskania rekordu z ID. Zamiast tego, można utworzyć rekord z ID.

W celu utworzenia ID zapisu, wymagany jest unikalny prefiks SObject, inaczej zostanie wygenerowany błąd. W celu odebrania odpowiedniego prefiksu, należy zastosować metodę klasy Schema:

sObjectType.getDescribe ().getKeyPrefix (), gdzie sObjectType może być pobrany z globalnego opisu lub z samej klasy SObject – Account. SObjectType.

Do tego celu może być wykorzystana prosta funkcja:

Po utworzeniu rekordu z ID, ID może być wykorzystany w relacji typu lookup lub relacji typu master-detail – w celu utworzenia struktur danych wymaganych do wykonywania testów.

Wszelkie SOQL zawarte w logice powinny być przeniesione do odrębnej klasy w nowej warstwie, o nazwie Data Access Layer. Te typy klas będą naszym punktem kontaktu z bazą danych. Bazując na poniższym przykładzie, zamiast:

Ta dodatkowa warstwa zapewnia ekstra korzyść. Po pierwsze, łatwiej jest utrzymywać pojedynczy punkt kontaktu z bazą danych niż mieć zapytania rozsiane w całym kodzie. Po drugie, opisowe metody, które będą wyszukiwać dane, mogą być uproszczone, ułatwiając naukę osobom pracującym z tym kodem w przyszłości. Po trzecie wreszcie, istnieje możliwość symulowania wyników wyszukiwania w Testach Jednostkowych – tak, że logika biznesowa może zostać przetestowana kompleksowo bez większego wpływu na wykorzystanie zasobów.

W podanym przykładzie można zastosować prostą klasę, na przykład:

Stub API

Chcąc przyspieszyć wykonanie Testów Jednostkowych za pomocą Stub API, należy zbudować symulacyjną strukturę ramową w celu ‘zasymulowania’ bazy danych. Mogą już istnieć testy wykorzystujące technikę symulowania wyników, ponieważ jest to standardowy sposób testowania kodu, który wykorzystuje wywołania do zewnętrznych systemów.

Ogólna koncepcja jest podobna: symulowane wyniki innych zewnętrznych systemów są wykorzystywane w celu sprawdzenia oczekiwanych wyników względem logiki biznesowej. W tym scenariuszu systemem zewnętrznym jest baza danych. W ramach przygotowania tworzonych jest kilka klas. Pierwszą będzie MockProvider – ta klasa umożliwia użytkownikom symulowanie wszystkich metod w symulowanej klasie poprzez mapowanie.

Następnym krokiem jest utworzenie klasy MockService, która będzie odpowiedzialna za symulowane wyniki funkcji w następujący sposób:

Jak widać, funkcja createMock jest wykorzystywana do utworzenia obiektu pozornego. Wykorzystanie Test.createStub wywołuje Stub API – system jest informowany, która klasa zostanie ‘zasymulowana’ oraz co zostanie zwrócone w przypadku określonych wywołań metod. Wykorzystanie tej usługi jest bardzo proste:

Po wywołaniu metody getRecords () z dataAccessLayerClassInstance w ramach testowanej klasy, rezultatem będzie resultForGetRecords.
We wspomnianym przykładzie muszą zostać dokonane pewne drobne korekty – wszystko w celu wykorzystania Stub API w testach. Zgodnie z powyższym należy zastosować klasę Data Access Layer zamiast wbudowanych SOQL.

Po wprowadzeniu zmian, wystarczy użyć klasy MockService w klasie Testu Jednostkowego i uzyskać szybkie wyniki, bez dotykania bazy danych.

Podsumowanie

Choć czas wykonania Testów Jednostkowych może być problematyczny, to dzięki zaprezentowanej w artykule metodzie, można znacząco przyspieszyć proces, a dzięki temu usprawnić swoją codzienną pracę.


Artykuł został pierwotnie opublikowany na stronie softserveinc.com. Zdjęcie główne artykułu pochodzi z unsplash.com.

Zapraszamy do dyskusji

Patronujemy

 
 
More Stories
Tworzenie cross-platformowej logiki w języku C++ dla natywnych aplikacji (cz.2)