Починаємо з 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'

Як бачите, так звані методи assertion як 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 (детальніше в таблиці podporované verze 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.