Přejít k navigační liště

Zdroják » PHP » Envtesting – ověřujeme nastavení prostředí

Envtesting – ověřujeme nastavení prostředí

Články PHP, Různé

Provozujete svoji aplikaci na více serverech? Máte samostatné prostředí pro produkci a pro vývoj? Kolikrát se vám stalo, že vaše aplikace vinou rozdílného nastavení nebo stavu prostředí nefungovala správně nebo nefungovala vůbec? Odhalení chyby prostředí může vám nebo administrátorovi zabrat dlouhé neproduktivní hodiny.

Při hledání chyby si budete klást řadu otázek:

  • Připojí se aplikace vůbec k databázi?
  • Nastavil jsem dobře přístupová práva?
  • Je povolen zápis do adresáře tmp nebo log?
  • Nezapomněl jsem přidat do PHP podporu PDO?
  • Přidal jsem podporu pro MongoDb?

Na většinu těchto otázek je možné odpovědět automatizovaně pomocí jednoduchého testu. Testování prostředí je z pohledu vývoje stejně důležité jako unit testování nebo integrační testy. Je vhodné jej zahrnout do procesu continuous delivery. Palčivost tohoto problému a neexistence vhodného nástroje v PHP nechala ve Wikidi vzniknout Envtestingu. Envtesting slouží právě pro jednoduché automatizované testování nastavení prostředí a ověřování minimálních požadavků pro provoz PHP aplikací.

Během programování Envtestingu jsme měli neustále na paměti, že tento nástroj budou používat nejen programátoři, ale také administrátoři. Ti obvykle nemají tolik programátorských zkušeností. Dalším požadavkem byla jednoduchost jak vytváření nového testu, tak použití existujícího. Ideálně by se mělo jednat o PHP script, který půjde spouštět samostatně. Posledním požadavkem byla rychlost nasazení na novém projektu. Pojďme se teď blíž podívat na to, co Envtesting vlastně umí.

Stažení Envtestingu

Celý Envtesting je obsažen v jediném minifikovaném PHP. Můžete si jej tedy snadno stáhnout například pomocí curl.

curl https://raw.github.com/wikidi/envtesting/master/Envtesting.php > Envtesting.php

Veškerý kód najdete také na GitHub https://github.com/wikidi/envtesting. Pro minifikaci Envtestingu používáme skript obsažený v nette/build-tools, které má na svědomí David Grudl. Děkujeme.

Píšeme první test

Pro napsání prvního testu vám postačí akorát vytvořit php soubor a instanci objekt \envtesting\Suite. Do \envtesting\Suite si pak můžete přidat prakticky libovolný test:

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');
$suite->addTest('booltest', function() {
    if (true != false) {
        throw new \envtesting\Error('Tento test je vzdy spatne');
    }
}, 'boolean');
// spusti vsechny testy a vypise jejich vysledek
echo $suite->run();

Funkce addTest očekává v druhém parametru anonymní funkci, callback nebo instanci objektu implementující funkci __invoke.

Povšimněte si, že uvedená anonymní funkce vždy vyhodí výjimku \envtesting\Error. Tato výjimka je při spuštění $suite->run(); zachycena a přetavena v chybu testu mybooltest. Pokud vytvořený kód spustíte prostřednictvím příkazové řádky, dostanete následující výsledek:

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                my great envtest
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ERROR      | booltest             | boolean    |  |  | Tento test je vzdy spatne

Při spouštění z příkazové řádky můžete narazit na rozdílné nastavení PHP pro Apache a PHP cli. S malou úpravou kódu můžete začít generovat výsledek jako HTML stránku. Místo echo $suite->run(); napište $suite->run()->render();

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');

$suite->addTest('booltest', function() {
    if (true != false) {
        throw new \envtesting\Error('Tento test je vzdy spatne');
    }
}, 'boolean');

// spusti vsechny testy a vypise jejich vysledek jako HTML
$suite->run()->render();

Výsledek pak vypadá následovně:

Povšimněte si tlačítka CSV – toto je třetím formátem, ve kterém můžete výsledky svých testů získat. Tento formát se vám může hodit pro automatické zpracování s výstupem do nějakého monitorovacího nástroje (např. Nagios).

Složitější testy

Součástí Envtestingu také sbírka několika základních envtestů. Tato sbírka mimo jiné obsahuje například test pro připojení k MySQL (test zápisu, čtení a mazání záznamů) nebo testy pro MongoDB. Testy jsou rozděleny do tří skupin na aplikační testy, testy knihoven a testy služeb.

Nejjednodušší testy nejdete v envtests/library. Účelem těchto testů je pouze ověření existence nějakého rozšíření v PHP. Příkladem je test sloužící k ověření dostupnosti Gettext:

<?php
namespace envtestslibrary;
// overi ze existuje rozsireni gettext a funkce gettext
\envtesting\Assert::true(
    \envtesting\Check::lib('gettext', 'gettext'),
    'Gettext library not found'
);

echo 'Gettext found';

Do svého envtestingSuite takový test přidáte velmi snadno:

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');
$suite->addTest(
        'Gettext',
        'envtests/library/Gettext.php',
        'library'
    );
$suite->run()->render();

Interně je skript Gettext.php obalen prostřednictvím anonymní funkce s pomocí include se provede ve chvíli spuštění testu. Tento test buď selže a vyhodí výjimku, nebo projde a veškerý vypsaný obsah je poté zobrazen jako výsledná message zpráva.

O stupínek složitější jsou testy ověřující funkčnost nějaké služby. Například tento test ověřující připojení k Memcache. Do svého Suite jej přidáte následovně:

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');
$suite->addTest('memcache', new envtestsservicesmemcacheConnection('127.0.0.1', 11211), 'service');
$suite->run()->render();

Poslední skupinou jsou aplikační testy, jejichž účelem je ověřit například schopnost zápisu do MySQL tabulky. Jejich použití je opět o stupínek složitější a například v případě testu pro MySQL požaduje vytvoření speciální tabulky.

Následující příklad ověří správnost nastavení přístupových práv k slave databázi:

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');
$slaveOperations = new envtestsapplicationmysqlOperations(
        "mysql://slave:slave@localhost:3306/database"
    );
$suite->addTest(
        'mysql:select',
        array($slaveOperations, 'selectAllow'),
        'application'
    )->setNotice('slave');
$suite->addTest(
        'mysql:insert',
        array($slaveOperations, 'insertNotAllow'),
        'application'
    )->setNotice('slave');
$suite->addTest(
        'mysql:delete',
        array($slaveOperations, 'deleteNotAllow'),
        'application'
    )->setNotice('slave');
$suite->addTest(
        'mysql:update',
        array($slaveOperations, 'updateNotAllow'),
        'application'
    )->setNotice('slave');
$suite->run()->render();
Ukázka zobrazení většího počtu testů

Předání parametrů

Občas se u nějakého testu může hodit možnost předat nějaké vstupní parametry při jeho spuštění. I na tento případ Envtesting pamatuje. Parametry můžete testům přidat rovnou při jejich přidávání do \envtesting\Suite prostřednictvím funkce \envtesting\Test->withOptions().

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');
$suite->addTest('test', function ($param1, $param2) {
    return sprintf('Predal jsi mi "%s" a "%s"', $param1, $param2);
})->withOptions('a', 'b')->setType('library');
$suite->run()->render();

Skupiny testů

Testy je možné řadit do skupin. Tyto skupiny testů je pak možné před spuštěním vzájemně promíchat pomocí metody \envtesting\Suite->shuffle().

Případně můžete \envtesting\Suite nastavit tak, aby při selhání nějakého testu ve skupině automaticky označil všechny následující stejnou chybou a nespouštěl je. Učiníte tak pomocí funkce \envtesting\Suite->failGroupOnFirstError()

<?php
require_once __DIR__ . '/Envtesting.php';
$suite = new \envtesting\Suite('my great envtest');

// group 1
$suite->group1->addTest(
        'APC',
        'envtests/library/Apc.php'
    )->setType('library')->setNotice('1/3');
$suite->group1->addTest(
        'GD',
        'envtests/library/Gd.php'
    )->setType('library')->setNotice('2/3');
$suite->group1->addTest(
        'Gettext',
        'envtests/library/Gettext.php'
    )->setType('library')->setNotice('3/3');

// group 2
$suite->group2->addTest(
    'PDO', function() {
        throw new \envtesting\Error('Die with me!');
    }
)->setType('library')->setNotice('1/3');
$suite->group2->addTest(
        'PDO',
        'envtests/library/Pdo.php'
    )->setType('library')->setNotice('2/3');
// alternativni zapis pridani testu do skupiny
$suite->to('group2')->addTest(
        'Mongo',
        'envtests/library/Mongo.php'
    )->setType('library')->setNotice('3/3');

$suite->setName('Group die test')
    ->shuffle()
    ->failGroupOnFirstError()
    ->run()
    ->render(); // fail group on first error

Co se jinam nevešlo

Envtesting toho umí ještě o něco víc. Ale už to jsou spíš drobnosti. Tak například \envtesting\Suite implementuje ArrayAccess a IteratorAggregate. Což se vám může hodit, pokud si budete chtít vypisovat po svém. Většina funkcí poskytuje fluent rozhraní. Statická funkce Suite::instance() vrací singleton objektu \envtesting\Suite  – ve většině případů vám totiž postačí pouze jediná instance Suite.

Padající test nemusí vždy bezpodmínečně končit vyhozením výjimky \envtesting\Error nebo Exception. Envtesting rozeznává ještě jeden stav testu a tím je vyhození varování \envtesting\Warning. Toto se může hodit v případě, kdy kontrolujete nějaký méně kritický požadavek.

Pokud test dopadne dobře, tak Envtesting automaticky zpracuje návratovou hodnotu anonymní funkce nebo callback funkce do zprávy o výsledku testu. V případě objektu se zajímá, zda implementuje metodu __toString(). Výsledek této metody opět využije pro sestavení zprávy o výsledku procházejícího testu.

Součástí Envtestingu je také jednoduchý Autoloader, který v základu nahlíží do pracovní složky Envtestingu. Prostřednictvím statické metody Autoloader::addPath() můžete přidávat další cíle pro autoloading PHP skriptů.

Poslední drobností, která stojí za zmínku, je \envtesting\Throws. Jedná se o jednoduchý error_handler, který zachytí všechna varování a notice a přetaví je v klasické výjimky Exception.

Komentáře

Subscribe
Upozornit na
guest
4 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Eda

„…chvílY spuštění testu“? :-)

Ale jinak fajn článek.

Radek

Podle článku to vypadá dobře, něco podobného jsem si chtěl napsat. Dík

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.