Начинаем работать с 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
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 тестов, один не удался, один был пропущен.

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

Режим Watch

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

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

Режим Watch запускается параметром –watch.

Отчеты CodeCoverage

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

Посмотрите пример 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.