​Google Test (poznatiji kao GTest) je Google-ov framework za testiranje, čiji je cilj da omogući jednostavno pisanje i izvršavanje jediničnih testova za C++ programe. Otvorenog je koda i javno dostupan na adresi https://github.com/google/googletest. Što se kompatibilnosti tiče, podržani su najzastupljeniji operativni sistemi – Linux distribucije, Mac i Windows, a od sistema za build – Bazel (koji se i interno od strane Google-ovih timova koristi), ali i CMake.

U Listingu 1 je data ilustracija tipične strukture test case-a implementiranog uz pomoć GTest-a. Kao što se može videti, u test case-u neophodno je omogućiti GTest biblioteku uključivanjem “gtest/gtest.h”, ali i sve ostale biblioteke čije se metode koriste u okviru samih testova.

Listing 1 Struktura tipičnog test case-a implementiranog uz pomoć GTest-a

Test case se definiše upotrebom makroa TEST, u okviru koga je potrebno definisati kod kojim se postižu željene provere. U ovim proverama je ključno uporediti vrednosti dobijene kao rezultat izvršenja koraka testa sa očekivanim vrednostima. Test je uspešan ukoliko se ove dve vrednosti poklapaju. Za ovu svrhu, koriste se dva tipa makroa: EXPECT_* i ASSERT_*. Razlika između njih je u tome što se kod ASSERT-a obustavlja izvršenje kada bar jedan test ne prođe, a kod EXPECT-a nastavlja. Svaki test case ima jedinstven naziv, može imati jednu ili više test metoda, a ukoliko naziv test metode počinje sa DISABLED_, onda se njeno izvršenje preskače.

U Tabeli 1 je dat pregled najčešće korišćenih provera kod GTest-a. Sve provere koje postoje za ASSERT, takođe su dostupne i za EXPECT.

Tabela 1 Najčešće korišćene provere u GTest-u

S obzirom da koristimo Bazel za build-ovanje i pokretanje testova, potrebno je dodati i nekoliko linija koda u WORKSPACE i BUILD fajlu, kao što je ilustrovano u Listingu 2. Što se WORKSPACE-a tiče, ovde dodajemo

Git repozitorijum GTest-a (sa parametrima koji obuhvataju naziv repozitorijuma, udaljenu lokaciju i verziju), dok u BUILD fajlu unutar zavisnosti (dependencies, označeno kao deps) navodimo naziv_repozitorijuma//:gtest, odnosno naziv_repozitorijuma//:gtest_main, ukoliko naš test program ne poseduje main. Osim toga, potrebno je u deps uključiti i sve ostale klase koje se koriste u testovima.

Listing 2 Bazel konfiguracija za GTest u programskom jeziku C++

Konačno, test pokrećemo uz pomoć Bazel-a komandom bazel test, pri čemu je argument komande naziv testa, definisan u okviru parametra name za cc_test element koji odgovara našem testu unutar BUILD fajla:

bazel test tests:moj_test

Primeri za GTest

1. C++ primer

U ovom primeru, pokazaćemo primenu GTest-a prilikom testiranja implementacije naše C++ biblioteke Matematika za jednostavne celobrojne aritmetičke operacije – sabiranje, oduzimanje, množenje i deljenje. Zatim, biće prikazani GTest testovi metoda ove biblioteke, build-ovani i pokrenuti korišćenjem Bazel-a.

U Listingu 3., prikazana je naša implementacije ove biblioteke, dok Listing 4. prikazuje BUILD fajl koji koristi Bazel prilikom build-ovanja biblioteke Matematika. Header fajl, koji nije prikazan, sadrži opis interfejsa ove klase, a nalazi na putanji src/lib/matematika.h. Kao što se može videti u Listingu 3., definiše se jedno cc_library build pravilo, pri čemu parameter name označava ime biblioteke (Matematika u ovom slučaju), srcs (sources) ima vrednost naziva fajla izvornog koda – matematika.cc, dok se hdrs (headers) odnosi na prethodno pomenuti header fajl – matematika.h. Sa druge strane, parametar visibility se odnosi na vidljivost biblioteke, a u ovom slučaju je podešena kao javna i može se koristiti i od strane drugih paketa.

 

Listing 3 Implementacija biblioteke Matemaika za jednostavne celobrojne operacije (na putanji src/lib/matematika.cc)

Listing 4 Bazel BUILD fajl za biblioteku matematika (na putanji src/lib/BUILD)

Listing 5. prikazuju primer test case-a koji obuhvata dve metode – saberi i deli. U prvom slučaju se sabiraju brojevi 2 i 3 upotrebom biblioteke, a zatim porede sa očekivanim rezultatom 5 upotrebom makroa EXCEPT_EQ(ocekivano, rezultat).  Očekuje se da su promenjive ocekivano i rezultat jednake. Zatim, u drugom slučaju se na sličan način vrši testiranje upotrebom biblioteke na primeru deljenja nulom. U našoj biblioteci, ova operacija je definisana tako da vraća nulu kao rezultat u ovom slučaju.

Listing 5 GTest jedinični testovi za biblioteku Matematika

Što se testa tiče, u BUILD fajlu je u okviru deps potrebno navesti biblioteku Matematika koju testiramo, ali i gtest_main, s obzirom da naš test nema main metodu. Sadržaj BUILD fajla ovog testa je prikazan u Listingu 6.

Listing 6 BUILD fajl jediničnog GTest testa za biblioteku Matematika (na putanji tests/BUILD)

Naravno, ne treba zaboraviti da WORKSPACE fajl mora sadržati build pravilo tipa git_repository u okviru koga navodimo lokaciju Git repozitorijuma GTest-a, kao što prikazuje Listing 7.

Listing 7 Sadržaj WORKSPACE fajla za build testa uz pomoć Bazel-a

Konačno, test build-ujemo i pokrećemo uz pomoć Bazel-a komandom bazel test, a zatim kao argument navedemo i naziv konkretnog testa. Nakon toga, Bazel štampa izveštaj o build-ovanju i izvršenim testovima (da li su prošli uspešno ili ne). Listing 8 prikazuje sadržaj konzole nakon uspešnog build-ovanja i izvršenja prethodno opisanog testa za biblioteku Matematika. Između ostalog, prikazuju se i pojedine dodatne informacije, poput ukupno potrošenog vremena i vremena izvršenja testa.

Listing 8 Build-ovanje i izvršenje GTest testova uz pomoć Bazel-a

Međutim, ukoliko uslov neke od provera nije ispunjen (odnos očekivanog i dobijenog), test će “pasti”, kao što je prikazano u okviru Listinga 9.

Listing 9 Uspešno build-ovan test koji pada jer uslov nije ispunjen

U liniji koja počinje crvenim FAIL se može kliknuti na putanju test log fajla, koji pruža dodatne detalje i uvid u razloge zbog čega test nije prošao, kao što je prikazano u Listingu 10. Otvaranjem log-a, u ovom primeru se može videti da je pao test za proveru množenja i to iz razloga jer je očekivana vrednost 5, a rezultat je 6 (dobijen množenjem 2 i 3), pri čemu se očekuje jednakost ovih vrednosti. Osim toga, u izveštaju se mogu videti ishodi svih izvršenih testova u okviru test case-a, ali i ukupan broj testova koju se prošli i pali.

Listing 10 Pregled log-a u slučaju testa koji je pao

2. C primer

Osim za C++, GTest se može koristiti i za jedinične testove C funkcija. U ovom primeru biće prikazano  testiranje C metoda nadji_max i nadji_min, koje pronalaze, redom, najveći i najmanji član u nizu celobrojnih elemenata. Kod ovih algoritama je napisan u čistom C-u, u okviru fajlova algoritmi.c i algoritmi.h.

Za C testove je karakteristično to da je neophodno primeniti kompajlersku direktivu extern C kojom se isključuje preklapanje imena funkcija, jer ih C ne podržava. Listing 10. prikazuje testove algoritama nadji_min i nadji_max. U prvom testu, poziva se nadji_min nad nizom {1, 3, 8}. Očekivani rezultat je najmanji član niza, što je 3 u ovom slučaju i upoređuje se sa dobijenim. Slično, za nadji_max se poziva nad istim nizom, ali se očekuje najveći element (u ovom slučaju 8) kao rezultat.

Listing 11 GTest testovi za C metode koje pronalaze najmanji, odnosno najveći element za dati niz

Autori: Maša Radenković, Nenad Petrović

Add comment