Начало работы с Nette Tester

Ошибаются и хорошие программисты. Разница между хорошим и плохим программистом в том, что хороший ошибётся один раз, а в следующий раз обнаружит ошибку автоматическими тестами.

  • “Кто не тестирует, обречён повторять свои ошибки.” (поговорка)
  • “Как только мы избавимся от одной ошибки, появится другая.” (закон Мёрфи)
  • “Всякий раз, когда вам хочется написать print, напишите вместо этого тест.” (Мартин Фаулер)

Вы когда-нибудь писали в 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
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, – 8.0 (подробности в таблице Поддерживаемые версии PHP). Предпочтительный способ установки – через Composer:

composer require --dev nette/tester

Попробуйте запустить Nette Tester из командной строки (без аргументов он выведет только справку):

vendor/bin/tester

Запуск тестов

По мере роста приложения растёт и количество тестов. Запускать тесты по одному было бы непрактично. Поэтому у Tester есть массовый запускатель тестов, который мы вызываем из командной строки. Параметром мы указываем каталог, в котором находятся тесты. Точка означает текущий каталог.

vendor/bin/tester .

Запускатель тестов обходит указанный каталог и все подкаталоги и ищет тесты, то есть файлы *.phpt и *Test.php. Он найдёт и наш тест ArrayTest.php, потому что тот подходит под маску.

Затем он начинает тестирование. Каждый тест запускается как новый процесс PHP, поэтому выполняется полностью изолированно от остальных. Запускает он их параллельно в нескольких потоках, благодаря чему работает чрезвычайно быстро. И сначала запускает тесты, которые провалились при предыдущем запуске, так что вы сразу узнаёте, удалось ли вам исправить ошибку.

Во время выполнения тестов Tester непрерывно выводит результаты в терминал символами:

  • . – тест прошёл
  • s – тест был пропущен
  • F – тест провалился

Вывод может выглядеть так:

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

PHP 8.5.2 (cli) | php | 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 тестов, один провалился, один был пропущен.

Мы продолжаем в главе Запуск тестов.

Режим наблюдения

Занимаетесь рефакторингом кода? Или, может, даже разрабатываете по методике TDD (Test Driven Development)? Тогда вам понравится режим наблюдения. В этом режиме Tester следит за исходными кодами и при их изменении запускается автоматически.

При разработке у вас в углу монитора терминал, в котором на вас светит зелёная полоса состояния, и когда она вдруг сменится красной, вы знаете, что только что сделали что-то не совсем так. По сути, это отличная игра, в которой вы программируете и стараетесь удержать цвет.

Режим наблюдения запускается параметром --watch.

Отчёты о покрытии кода

Tester умеет порождать отчёты с обзором того, какую часть исходного кода покрывают тесты. Отчёт может быть либо в понятном человеку формате HTML, либо в Clover XML для дальнейшей машинной обработки.

Посмотрите пример HTML-отчёта с покрытием кода.

Поддерживаемые версии PHP

Версия Совместима с PHP
Tester 2.6 PHP 8.0 – 8.5
Tester 2.5 PHP 8.0 – 8.5
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 поддержка прекращена.