Написання модульних тестів за допомогою PHPUnit, частина 3: Конфігурація XML
У минулих публікаціях із цієї серії я розглядав такі дві теми:
- Написання модульних тестів за допомогою PHPUnit, частина 1: Налаштування. Посібник із початку написання тестів PHPUnit за допомогою базового кешу та методу setUp фреймворку.
- Написання модульних тестів за допомогою PHPUnit, частина 2: The Tear Down. Підручник про те, як писати модульні тести, які належним чином використовують методи setUp і tearDown PHPUnit.
Кожне з перерахованого вище призначено для того, щоб надати початкову інформацію про те, як розпочати написання простих модульних тестів. Речі можуть ускладнюватися, особливо коли програма чи проект розвиваються (але це завжди так, чи не так?).
Але щоб переконатися, що людина готова до цього, є один останній компонент модульного тестування, на якому, я вважаю, ми повинні зосередитися, і це розуміння файлу конфігурації PHPUnit XML (який ви, можливо, бачили в інших проектах як phpunit.xml).
Конфігурація PHPUnit XML
Тому в цій публікації я збираюся налаштувати простий проект, який використовує PHPUnit, пише кілька тестів, подібних до тих, які ми вже бачили, і використовує файл конфігурації для автоматизації тестування.
Крім того, я зроблю все можливе, щоб якнайкраще пояснити необхідні частини файлу конфігурації, щоб ви могли включити їх у свій наступний проект.
1 Видалення файлів
Перш ніж приступити до написання перевіреного коду, важливо знати файли, які знадобляться, щоб запустити процес.
Нижче наведено більш-менш те, як ми організовуємо речі з самого початку проекту:
- довідник для тестів,
- файл phpunit.xml _
Згодом ви також побачите:
- файли, які складають проект,
- тести, які перевіряють ці файли.
Однак на цьому етапі давайте подивимося на файл конфігурації XML, а потім спробуємо автоматично запустити PHPUnit без будь-яких інших параметрів.
2 Основи файлу конфігурації
Спочатку розглянемо основний файл конфігурації:
<?xml version="1.0" encoding="UTF-8"?>
<!-- http://phpunit.de/manual/4.1/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
bootstrap="./tests/bootstrap.php"
backupGlobals="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
>
<testsuites>
<testsuite name="AcmeTests">
<directory>./tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="true"></log>
</logging>
</phpunit>
Тепер давайте зрозуміємо, на що саме ми дивимося (окрім простого XML).
- phpunit. Батьківський вузол виконує звичайну роботу з визначення схеми для XML-файлу, але є кілька інших компонентів, які нас цікавлять:
- backupGlobals. Насправді це пов’язано з анотацією, яку ми можемо зробити у вихідному коді. Глобальні значення — це те, чого ми повинні намагатися уникати в об’єктно-орієнтованому програмуванні, але якщо ви вирішите використовувати один або потребуєте його, тоді це вкаже PHPUnit обробляти значення, які зберігають глобальні змінні (і дасть вам можливість відновити їх). Зазвичай я залишаю це як є.
- bootstrap. Це необов’язково, але якщо ви вирішите включати інші файли у свої тести (наприклад, додавання імітаційної бібліотеки, частини WordPress або сторонньої бібліотеки), тоді це все, що ви зможете визначити розташування сценарію, який має виконувати. Знущання та впровадження WordPress виходять за рамки цієї публікації, але ми, ймовірно, розглянемо це в майбутньому, оскільки це корисно під час тестування плагінів. Наразі я додам простий автозавантажувач, який фактично додає всі файли в кореневий каталог проекту. Повне джерело для цього буде опубліковано пізніше в цій публікації.
- кольори. Якщо ви хочете, щоб консоль роздрукувала звіт про ваші тести з використанням кольорів (щоб легше ідентифікувати попередження, зауваження, помилки тощо), тоді встановіть значення true.
- Нижче наведено всі логічні значення. Я рекомендую встановити для них значення true для максимально агресивних звітів. Таким чином, вам не вдасться просто проскочити сповіщення або попередження, хвилюючись лише про помилки. Це більше вправа на якість коду, ніж будь-що інше.
- convertErrorsToExceptions
- convertNoticesToExceptions
- convertWarningsToExceptions
- набори тестів складаються з колекцій тестів. Оскільки певний проект може мати кілька тестів, важливо переконатися, що ви даєте кожному пакету унікальне ім’я та вказуєте правильний шлях до групи тестів. Для нашого прикладу ми матимемо лише один набір тестів, і він розташований у каталозі tests .
- ведення журналу — це функція, яка може бути такою ж простою, як друк даних на консолі або використання сторонньої бібліотеки (наприклад, Clover) для створення звітів, які допомагають безперервній інтеграції. Оскільки я ще не обговорював останній у своїх попередніх публікаціях, ми збираємося дотримуватися консолі як нашого основного методу виведення. Таким чином, ми маємо php ://stdout як єдиний вихід журналу.
З огляду на все це, наш XML-файл містить усе, що PHPUnit потрібно для роботи без будь-яких інших параметрів.
Однак пам’ятайте, що перш ніж продовжити цю статтю, я припускаю, що ви глобально встановили PHPUnit у своїй системі за допомогою Composer. Якщо ні, перегляньте цю статтю, оскільки вона надасть вам інструкції, як це зробити.
Після цього ви можете переконатися, що PHPUnit встановлено, ввівши таку команду у свій термінал:
$ which phpunit
І ви повинні побачити щось на зразок наступного:
Якщо ви бачите щось подібне до наведеного вище, тоді ви можете запустити PHPUnit будь-де зі своєї системи.
3 Файл Bootstrap
Перш ніж йти далі, давайте напишемо базовий файл початкового завантаження. Ми назвемо його bootstrap.php і розмістимо в нашому каталозі тестів . Він включатиме наступне:
<?php
// This array has a single file but could whole the contents of an entire directory.
$files = [
dirname(__DIR__).'/AcmeCache.php',
];
foreach ($files as $file) {
if (file_exists($file)) {
require_once $file;
}
}
Це простий «автозавантажувач» (який я нерішуче так називаю, враховуючи, що він просто переглядає файли та вимагає їх, але він працює для наших цілей).
На цьому етапі давайте налаштуємо базовий тест.
4 Базовий тест, який не проходить
Якщо ви читаєте щось про розробку, керовану тестуванням, то, швидше за все, почуєте про цикл «червоно-зелено-повторення». Про це можна багато говорити, і я рекомендую прочитати, але це не мета цієї публікації.
Натомість ми більше зосереджені на написанні тестів, які відповідають тому, що нам потрібно зробити, чи не так? З огляду на це, давайте зробимо наступне:
- створіть каталог, у якому ви матимете деякі базові файли PHP, які ми перевіримо,
- у корені каталогу також створіть phpunit.xml і заповніть його, використовуючи код, наданий раніше в цій публікації
- створити каталог тестів, де ми розмістимо наші тести.
Тепер у терміналі змініть каталог на каталог проекту (який, правда, наразі відсутній), а потім просто запустіть php unit:
$ phpunit
Якщо припустити, що все налаштовано правильно, ви повинні побачити щось на зразок цього:
Оскільки у нас немає ні коду, ні тестів, ми, природно, побачимо результат вище, чи не так? Отже, давайте напишемо єдиний тест, який виконуватиметься (і не вдасться), оскільки для нього немає коду для тестування.
Спочатку в каталозі tests створіть файл під назвою AcmeCacheTest.php. І нехай він зробить щось просте, наприклад, створить екземпляр об’єкта кешу, який ми зрештою створимо.
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
}
Перш ніж запускати тест, зауважте, що ми:
- Обов’язково використовуйте PHPUnitFrameworkTestCase
- І наш клас розширить TestCase
Це частина того, що робить використання PHPUnit таким простим. Коли це буде зроблено, запустіть наступний код із кореня вашого проекту:
$ phpunit
Після цього ви повинні побачити наступне:
Зауважте, що це дасть результат невдалого тесту та повідомить вам, де виявлено проблему, файл і рядок.
Щоб виправити це, нам потрібно написати клас:
<?php
namespace Acme;
class AcmeCache
{
private $duration;
public function __construct()
{
$this->duration = 43200;
}
public function setDuration(int $duration)
{
$this->duration = $duration;
}
public function getDuration(): int
{
return $this->duration;
}
}
4 Кілька базових іспитів
Основний тест (який базуватиметься на попередньому коді) включатиме наступне:
- файл із простором імен,
- представлятиме простий кеш,
- буде автоматично завантажено PHPUnit за допомогою наданого вище файлу bootstrap.php
- і матиме встановлену тривалість у своєму конструкторі разом із установником і джерелом отримання значення
По-перше, давайте перевіримо, чи ми можемо налаштувати клас і чи він не нульовий. Це дещо непотрібне твердження, оскільки ми знаємо, що ми матимемо належним чином створений екземпляр класу, але воно залучає нас до написання тестів:
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
}
І запустіть тест:
Далі перевіримо, що значення кешу встановлено за замовчуванням:
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
public function testDefaultCacheValue()
{
$this->assertSame(43200, $this->cache->getDuration());
}
}
Як і в попередньому кроці, запустіть тести, і тепер ви повинні побачити два успішних тести:
Нарешті, давайте перевіримо, чи зможемо ми успішно змінити значення:
<?php
namespace AcmeTests;
use PHPUnitFrameworkTestCase;
use AcmeAcmeCache;
class AcmeCacheTest extends TestCase
{
private $cache;
public function setUp()
{
$this->cache = new AcmeCache();
}
public function testCacheExists()
{
$this->assertNotNull($this->cache);
}
public function testDefaultCacheValue()
{
$this->assertSame(43200, $this->cache->getDuration());
}
public function testSetCustomDuration()
{
$duration = 4200;
$this->cache->setDuration($duration);
$this->assertSame($duration, $this->cache->getDuration());
}
}
І останні три здачі:
І ось у вас це:
- XML-файл PHPUnit,
- простий завантажувач,
- єдиний клас із простором імен,
- модульні тести для кожного методу класу
Зрозуміло, це просто, але це закладає основи для набагато більшого, ніж те, що багато людей вже роблять зі своїми тестами.
Більше того, це дає вам можливість розвиватися, коли ваші результати тестування стають сильнішими.
Чи є більше? (Завжди правий?)
Нарешті, якщо ви хочете по-справжньому зануритися у файл конфігурації, ви можете прочитати детальне пояснення цього посібника.
Зауважте, однак, що все, що описано вище, є тим, що вам потрібно для початку налаштування власного файлу конфігурації PHPUnit XML.




