Narzędzia do przeprowadzania Unit testów PHPUnit - uruchamianie Przygotowanie Dla narzędzia PHPUnit wymagany jest interpreter PHP (pobierz archiwum ZIP, wypakuj narzędzie *.phar oraz nadaj uprawnienia wykonywalne) Utwórz katalog do pracy, np. 25-phpunit oraz umieść tam pobierane narzędzia oraz wyniki pracy Zapoznaj się z listą dostępnych asercji oraz Skryptami do przetestowania 1 Zadania do wykonania testów Zapoznaj się z zadaniami, następnie zaimplementuj Unit testy. mechanizm ładowania arkusza CSS oraz biblioteki JS przez metodę loadLib() - napisz i przetestuj (CaT, code & test) weryfikacja poprawnego generowania formularzy przez klasę FormBuilder - przetestuj i popraw (TaP, test & patch) moduł pobierania istniejącej strony HTML z Internetu uGet - napisz, przetestuj i popraw (CTF, code-test-fix) moduł przesyłania plików z zadaniami na Hosting uSend - napisz, przetestuj i popraw (CTF, code-test-fix) testy do własnej aplikacji - skonsultuj się z prowadzącym 2 Przygotowanie środowiska testowego Poniższa struktura jest przykładowa - jeżeli czcisz nieporządek i rozgardiasz - możesz wrzucić wszystkie pliki do jednego katalogu. /PHPUnit +--app (pliki z kodem aplikacji) | |--MojaApka.php | \--Pakiet.php +--res (katalog wyników testów) | |--result-1.html | \--result-1.xml +--tests (katalog z testami i asercjami) | |--MojaApkaTest.php | \--PakietTest.php +--tools | \-- phpunit.phar (uruchamiane narzędzie) phpunit.xml (opcjonalny plik z ustawieniami narzędzia) 3 Uruchamianie testów Wywołanie testów możliwe jest dla tego narzędzia na kilka sposobów: Proste wywołanie pojedynczego testu; wyniki do terminala ./tools/phpunit.phar tests/MojaApkaTest.php Wywołanie wszystkich testów z katalogu tests z przełącznikiem --colors kolorowania wyników w terminalu ./tools/phpunit.phar --colors tests Wywołanie wszystkich testów z przełącznikiem --testdox generujacym wyniki do pliku XML ./tools/phpunit.phar --colors tests --testdox Wywołanie pojedynczego testu z przełącznikiem --testdox-html generujacym wyniki do pliku HTML ./tools/phpunit.phar --colors tests/MojaApkaTest.php --testdox-html Wywołanie testów z przełącznikiem --testdox-html res/wyniki.html generujacym wyniki do pliku w katalogu res/wyniki.html ./tools/phpunit.phar --colors tests --testdox-html res/wyniki.html Wywołanie testów skonfigurowanych w pliku phpunit.xml* ./tools/phpunit.phar * plik musi istnieć w katalogu głównym projektu, skąd wywołuje się narzędzie oraz posiadać następującą strukturę: <?xml version="1.0" encoding="UTF-8" ?> <phpunit colors="true" stopOnFailure="false"> <testsuites> <testsuite name="Nazwa-Testu"> <directory>tests</directory> <file></file> </testsuite> </testsuites> </phpunit> 4 Implementacja asercji Przykładowa asercja: <?php // Kod testów jednostkowych use PHPUnit\Framework\TestCase; // użyj biblioteki PHPUnit w tym skrypcie require('app/lib-1.php'); // załącz plik z kodem do przetestowania // klasa testująca Klasę powinna kończyć się słowem `Test` class FormTest extends TestCase { // klasa musi dziedziczyć metody z klasy TestCase public function testDisplayEmptyForm() { // pojedyncze testy zaczynają się słowem `test` po którym następuje nazwa testu $f = new Form("Testowy formularz"); $form = $f->display(); $formToCompare = "<form><h2>Testowy formularz</h2></form>"; $this->assertEquals( $formToCompare, $form ); } public function testDisplayFormAndControls() { $f = new Form("Testowy formularz"); $label = '<label>Etykieta</label>'; $input = '<input type="text" name="entry" />'; $f->pack($label,$input); $form = $f->display(); $formToCompare = "<form><h2>Testowy formularz</h2><label>Etykieta</label><input type="text" name="entry" /></form>"; $this->assertEquals( $formToCompare, $form ); } } Zaimplementuj oraz wykonaj testy i asercje dla pozostałych klas. Jeżeli trzeba - popraw powyższy kod. Testy wymagają stworzenia nowych instancji oraz ich skasowania po teście* Instancjonowanie klasy na rządanie testów public function setUp() : void { $this->instance = new KlasaWymaganaDoTestow(); } Destrukcja klasy public function tearDown() : void { unset($this->instance); } *!!!UWAGA!!! Zapis metod Instancji i Destrukcji klasy musi być dokładnie taki, jak przedstawiono na w/w listingach. 5 Testowanie metod prywatnych Testowanie prywatnych metod* wymaga użycia tzw. mechanizmu Refleksji (Reflection) dostępnego w wielu obiektowych językach programowania. public function invokeMethod(&$object, $methodName, array $parameters = array()) { $reflection = new \ReflectionClass(get_class($object)); $method = $reflection->getMethod($methodName); $method->setAccessible(true); return $method->invokeArgs($object, $parameters); } *!!!UWAGA!!! Zapis tzw. Refleksji dostępu do prywatnej metody musi być dokładnie taki, jak przedstawiono na w/w listingu. Użycie Reflekcji // testowanie publicznych metod public function testMojaMetodaPubliczna(){ $this->assertEquals( $wzorzec, $this->mojaMetodaPubliczna('parametr') ); } // testowanie prywatnych metod z użyciem tzw. Refleksji public function testMojaMetodaPrywatna(){ $this->assertEquals( $wzorzec, $this->invokeMethod( $this->instance, 'mojaMetodaPrywatna', ['parametr'] ) ); 6 Zadanie warsztatowe Zadanie 1a mechanizm ładowania arkusza CSS oraz biblioteki JS przez metodę loadLib() - napisz i przetestuj (CaT, code & test) Zaimplementuj metodę loadLib(), której zadaniem jest renderowanie znaczników LINK oraz SCRIPT dla przykładowych kombinacji przedstawionych poniżej: // przykładowe wyniki metody `loadLib()` <link rel="stylesheet" href="ui/katalog/plik.css" /> <link rel="stylesheet" href="ui/katalog/plik.css?v=123" /> <script src="ui/katalog/plik.js" /></script> <script src="ui/katalog/plik.js?v=123" /></script> Deklaracja metody oraz jej wywołanie: public function loadLib( $type, $filePath, $version=null ){} ... loadLib('css','katalog/arkusz'); loadLib('js','katalog/biblioteka',['ver'=>123]); Zadanie 1b Rozszerz implementację metody oraz testów o obsługę: // A/ test i metoda generująca dodatkowo atrybut media="print" loadLib('css-prn','katalog/plik',['ver'=>123]); // B/ test sprawdzający brak pliku - w tym przypadku test ma przejść pozytywnie