Artykuły o technologiach IT, programowaniu, testowaniu i nie tylko

Witam w drugiej części artykułu poświęconego Codeception. Tym razem przyjrzymy się już konkretnym przykładom użycia, oraz nauczymy się jak tworzyć testy jednostkowe oraz generować raporty pokrycia testami. Nie marnując już więcej słów, przejdźmy do praktyki! Będzie dużo kodu.

1. Wymagania wstępne

Co będzie nam potrzebne?

1. Środowisko z poprzedniego artykułu http://rst.com.pl/piszemy/2016/08/08/yii2-advanced-template-codeception-windows-czesc-pierwsza/
2. Ulubiona konsola
3. IDE lub edytor (Netbeans, PHPStorm, Notepad++, etc.)

2. Podstawowe instrukcje

Aby stworzyć test potrzebujemy wiedzieć jak go napisać. W najprostszej postaci test wygląda następująco:

Nazwę klasy oraz pliku tworzymy w formacie „<nazwa_testu>Test”, czyli na przykład „SampleTest”. Test musi rozszerzać jedną z dostępnych klas testowych:
\yii\codeception\TestCase lub \yii\codeception\DbTestCase.

Zmienna $appConfig jest również wymagana i wskazuje na konfigurację aplikacji w Yii.

Następnie widzimy funkcję, która jest naszym testem. Funkcje powinny zaczynać się od nazwy test, oraz w dalszej części nazwą tego testu. Alternatywnie, zamiast zaczynać nazwy funkcji od słowa test możemy poprzedzić ją komentarzem:

Stwórz teraz plik „SampleTest” w ścieżce <aplikacja_yii>/tests/codeception/common/unit/models/
Następnie uruchom konsolę, przejdź do folderu <aplikacja_yii>/tests/codeception/common i wpisz komendę:

W wyniku powinienieś otrzymać:

Test run
Zostały uruchomione domyślne testy Yii oraz nasz SampleTest, który przeszedł pomyślnie. Wiemy już jak wygląda podstawowy test jednostkowy, teraz niech coś przetestuje! Przy pisaniu testów możemy korzystać z całej gamy asercji, której listę znajdziemy tutaj.

Asercja (ang. assertion) – predykat (forma zdaniowa w danym języku, która zwraca prawdę lub fałsz), umieszczony w pewnym miejscu w kodzie. Asercja wskazuje, że programista zakłada, że predykat ów jest w danym miejscu prawdziwy.

– źrodło: Wikipedia.

Stwórzmy więc pierwszy test.

Sprawdzamy, czy statyczna metoda tableName zwróci nam wartość „sample”. Uruchamiamy test aby zobaczyć, że test nie przechodzi, oraz że nie mamy „SampleModel”. Dostaniemy stosowny komunikat.

Stwórzmy więc model w <applikacja_yii>/common/models/SampleModel.php

Ponownie uruchamiany test i powinniśmy otrzymać:

First test run
Właśnie napisałeś swój pierwszy test jednostkowy! Teraz sprawmy, żeby ten test mówił o sobie coś więcej. Użyjemy do tego modułu specify. Pozwala on na pisanie testów w stylu BDD.

 

3. Specify

Ważna uwaga dotycząca specify.
Domyślnie, specify używa „głębokiego klonowania” (z ang. deep cloning) do skopiowania obiektów do bloków specify, dzięki czemu są od siebie odizolowane. Dokładniej rzecz ujmując, spójrzmy na poniższy przykład:

Widzimy tutaj zmienną $object, której właściwość id jest ustawiana na 1, a następnie zmieniana na 2 w pierwszym bloku kodu specify. Jednak ten obiekt jest jedynie kopią. Dlatego w drugim bloku specify, sprawdzamy ponownie wartość id, która równa się 1.
Wynik testu:

cloning test

Jeżeli chcemy, aby nie był kopiowany, możemy to zrobić za pomocą poniższej linii kodu:

Teraz obiekt nie zostanie skopiowany, nie będziemy mieli więc dostępu do atrybutu id.

I wynik testu:

result
Teraz zmiana wartości w pierwszym bloku kodu, zmieniła naszą wartość, więc drugi blok zwrócił błąd.

Używanie deep cloning znacznie zwiększa jednak zużycie pamięci.

 

4. Fixtures

Kolejnym elementem do przeprowadzenia testów jednostkowych przy połączeniu z bazą danych jest użycie predefiniowanych danych. Aby nie musieć za każdym razem wprowadzać ich do bazy danych, lub co gorsza, resetować w teście do stanu początkowego (O zgrozo).

Jeżeli użyjemy fixtures w danej klasie testowej, to przed każdym testem dane z tabel, które odpowiadają fixturą, zostaną wyczyszczone i wprowadzone na nowo.

Zacznijmy od skonfigurowania bazy danych. Konfiguracje bazy danych znajdziemy w:

Ustawiamy połączenie do naszej bazy danych, następnie tworzymy w niej następującą tabelę:

Następnie w naszym pliku testowym „SampleTest” dodajemy linijkę:

Ta klasa definiuje jakiego modelu użyć dla klasy UserFixture.

Kolejnie do testu dopisujemy funkcję, w której konkretnie wskazujemy z jakich fixtursów chcemy skorzystać.

Tworzymy teraz plik w katalogu tests/codeception/common/unit/fixtures/data/models/ o nazwie sample_user.php – jest to plik z danymi do naszej bazy danych. Plik ten zwraca tablicę, w której każdym elementem jest tablica o konstrukcji nazwa_pola_w_bazie => wartość.
Na początek dodajmy tam jednego usera.

Ostatnim już krokiem jest napisanie testu.

Teraz, przed każdym testem z naszej klasy, tabela user zostanie wyczyszczona i ponownie wypełniona danymi. Aby to sprawdzić napiszemy kolejny test.

Wstawiamy tę funkcję przed testSampleUser. Uruchamiamy testy i jak widzimy, wszystkie kończą się powodzeniem – nawet jeżeli zmodyfikujemy dane na bazie,
w pierwszym teście.

Teraz możemy umieścić tam dowolne dane.
Podsumowując: aby dodać fixtury do nowej tabeli potrzebujemy:
Stworzyć klasę tests\codeception\common\fixtures\NazwaModeluFixture.php, która będzie zawierać

Następnie w klasie testu dodać :

oraz funkcję wskazującą na dane

i ostatecznie dodać plik:

w którym zwrócimy dane dla tego modelu

5. Code Coverage

Ostatnim elementem tego wpisu będzie wygenerowanie pokrycia kodu w postaci ładnej graficznej reprezentacji. Jeżeli mamy włączony Xdebug w php:
wpisanie w konsoli polecenie

powinno pokazać nam:

phpconfig

To jedyne co musimy zrobić, to dodać następujące wpisy konfiguracyjne do Codeception.
W pliku

dodajemy następujące wpisy

Robimy to na poziomie testów common, dla unit testów, ponieważ na razie nie uruchamiamy jeszcze pełnych testów (akceptacyjnych czy funkcjonalnych);

Teraz w konsoli wpisujemy polecenie:

Plik zostanie wygenerowany w \tests\codeception\common\_output\coverage i powinien wyglądać mniej więcej tak:

codecoverage

W kolejnej części artykułu, dowiemy się jak skonfigurować i uruchomić testy akceptacyjne i funkcjonalne, oraz przyjrzymy się bliżej co właściwie wiemy z takiego raportu.


Nawigacja