Започваме с Nette Tester

И добрите програмисти правят грешки. Разликата между добрия и лошия програмист е в това, че добрият я прави само веднъж и следващия път я открива с помощта на автоматизирани тестове.

  • “Който не тества, е осъден да повтаря грешките си.” (поговорка)
  • “Щом се отървем от една грешка, се появява друга.” (Закон на Мърфи)
  • “Винаги, когато имате нужда да изпишете на екрана променлива, напишете по-скоро тест.” (Мартин Фаулър)

Написали ли сте някога в PHP подобен код?

$obj = new MyClass;
$result = $obj->process($input);

var_dump($result);

Тоест, изписали сте резултата от извикването на функция само за да проверите с око дали връща това, което трябва? Със сигурност го правите много пъти на ден. Ръка на сърцето: в случай, че всичко работи правилно, изтривате ли този код? Очаквате ли, че класът няма да се счупи в бъдеще? Законите на Мърфи гарантират обратното :-)

Всъщност сте написали тест. Просто трябва леко да го промените, така че да не изисква визуална проверка, а да се проверява сам. И ако не изтриете теста, можете да го стартирате по всяко време в бъдеще и да проверите дали всичко все още работи, както трябва. С времето ще създадете голям брой такива тестове, така че би било добре да ги стартирате автоматизирано.

И с всичко това ще ви помогне именно Nette Tester.

С какво е уникален Tester?

Писането на тестове за Nette Tester е уникално с това, че всеки тест е обикновен PHP скрипт, който може да бъде стартиран самостоятелно.

Тоест, когато пишете тест, можете просто да го стартирате и да установите дали например в него няма програмна грешка. Дали работи правилно. Ако не, можете лесно да го дебъгвате във вашето IDE и да търсите грешката. Можете дори да го отворите в браузър.

И преди всичко – с това, че го стартирате, изпълнявате теста. Веднага установявате дали е преминал, или се е провалил. Как? Нека да покажем. Ще напишем тривиален тест за работа с PHP масив и ще го запазим във файла ArrayTest.php:

<?php
use Tester\Assert;

require __DIR__ . '/vendor/autoload.php';  # зареждане на Composer autoloader
Tester\Environment::setup();               # инициализация на Nette Tester

$stack = [];
Assert::same(0, count($stack));   # очакваме, че count() ще върне нула

$stack[] = 'foo';
Assert::same(1, count($stack));   # очакваме, че count() ще върне единица
Assert::contains('foo', $stack);  # проверяваме дали $stack съдържа елемент 'foo'

Както виждате, т.нар. асерционни методи като Assert::same() се използват за потвърждаване, че действителната стойност съответства на очакваната стойност.

Тестът е написан и можем да го стартираме от командния ред. Първото стартиране ще ни разкрие евентуални синтактични грешки и ако не сте направили печатна грешка никъде, ще се изпише:

$ php ArrayTest.php

OK

Опитайте в теста да промените твърдението на невярно Assert::contains('XXX', $stack); и наблюдавайте какво ще се случи при стартиране:

$ php ArrayTest.php

Failed: ['foo'] should contain 'XXX'

in ArrayTest.php(17) Assert::contains('XXX', $stack);

FAILURE

Продължаваме да пишем за писането в главата Писане на тестове.

Инсталация и изисквания

Минималната версия на PHP, изисквана от Tester, е 7.1 (по-подробно в таблицата поддържани версии на PHP). Предпочитаният начин за инсталиране е чрез Composer:

composer require --dev nette/tester

Опитайте да стартирате Nette Tester от командния ред (без параметри само ще изпише помощ):

vendor/bin/tester

Стартиране на тестове

С нарастването на приложението броят на тестовете расте с него. Не би било практично да стартирате тестовете един по един. Затова Tester разполага с групов стартер на тестове, който извикваме от командния ред. Като параметър посочваме директорията, в която се намират тестовете. Точката означава текущата директория.

vendor/bin/tester .

Стартерът на тестове претърсва зададената директория и всички поддиректории и търси тестове, които са файлове *.phpt и *Test.php. Така намира и нашия тест ArrayTest.php, тъй като отговаря на маската.

След това стартира тестването. Всеки тест стартира като нов PHP процес, така че протича напълно изолирано от останалите. Стартира ги паралелно в няколко нишки и благодарение на това е изключително бърз. И като първи стартира тестовете, които при предишното изпълнение са се провалили, така че веднага разбирате дали сте успели да поправите грешката.

По време на изпълнение на тестовете Tester изписва непрекъснато резултатите на терминала като знаци:

  • . – тестът премина
  • s – тестът беше пропуснат (skipped)
  • F – тестът се провали (failed)

Изходът може да изглежда така:

 _____ ___  ___ _____ ___  ___
|_   _/ __)( __/_   _/ __)| _ )
  |_| \___ /___) |_| \___ |_|_\  v2.5.2

Note: No php.ini is used.
PHP 8.3.2 (cli) | php -n | 8 threads

........s................F.........

-- FAILED: greeting.phpt
   Failed: 'Hello John' should be
       ... 'Hello Peter'

   in greeting.phpt(19) Assert::same('Hello Peter', $o->say('John'));

FAILURES! (35 tests, 1 failures, 1 skipped, 1.7 seconds)

Бяха стартирани 35 теста, един се провали, един беше пропуснат.

Продължаваме по-нататък в главата Running Tests.

Watch режим

Рефакторирате код? Или дори разработвате според методологията TDD (Test Driven Development)? Тогава ще ви хареса watch режимът. Tester в него следи изходните кодове и при промяна се стартира сам.

При разработка така имате в ъгъла на монитора терминал, където ви свети зелен статусен ред, и когато внезапно се промени на червен, знаете, че току-що не сте направили нещо съвсем добре. Това всъщност е страхотна игра, при която програмирате и се опитвате да поддържате цвета.

Watch режимът се стартира с параметъра –watch.

CodeCoverage отчети

Tester може да генерира отчети с преглед колко от изходния код покриват тестовете. Отчетът може да бъде или в човешки четим формат HTML, или Clover XML за по-нататъшна машинна обработка.

Вижте coverage.html с покритие на кода.

Поддържани версии на PHP

версия съвместима с PHP
Tester 2.5 PHP 8.0 – 8.3
Tester 2.4 PHP 7.2 – 8.2
Tester 2.3 PHP 7.1 – 8.0
Tester 2.1 – 2.2 PHP 7.1 – 7.3
Tester 2.0 PHP 5.6 – 7.3
Tester 1.7 PHP 5.3 – 7.3 + HHVM 3.3+
Tester 1.6 PHP 5.3 – 7.0 + HHVM
Tester 1.3 – 1.5 PHP 5.3 – 5.6 + HHVM
Tester 0.9 – 1.2 PHP 5.3 – 5.6

Важи за последната пач версия.

Tester до версия 1.7 поддържаше също HHVM 3.3.0 или по-висока (чрез tester -p hhvm). Поддръжката беше прекратена от версия Tester 2.0.