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

Zdroják » PHP » Testování v PHP: testy integrace s databází II.

Testování v PHP: testy integrace s databází II.

Články PHP, Různé

V minulém díle jsme se seznámili se základy testování integrace s databází pomocí rozšíření DbUnit, dnes se podíváme na jeho další možnosti.

Abstraktní předek pro integrační testy

Ještě než začneme, tak si připravíme abstraktního předka, od kterého budou všechny naše integrační testy dědit. Důvod je prostý – nechceme dokola opisovat stále stejné metody pro přípravu fixture, což svádí ke copy-paste a to je téměř vždy cesta do pekel. Pokud budeme potřebovat pro nějakou sadu testů jiný inicializační dataset, pak jednoduše překryjeme metodu getDataset.

Máme-li větší množství integračních testů, můžeme narazit na problém s příliš velkým počtem otevřených spojení s databází. Tomuto je možné čelit dvěma způsoby. Buď budeme spojení vždy zavírat v metodě tearDown, nebo si připojení uložíme do statické property abstraktní třídy DatabaseTestCase.

Obecně uznávané, nebo spíše tolerované, řešení je pomocí statické property. Získáme tím sice jedno připojení pro všechny testy, ale na druhou stranu pošlapeme jedno ze základních pravidel dobrých testů – nezávislost. Opravdu není dobrým zvykem v testech cokoli sdílet.

Možná vás napadne – proč tedy ukládat instanci DefaultDBConnection, před každým test case bude přece vytvořena znovu? Odpověď je nasnadě – instanci DefaultDBConnection (tzv. Connection API) budeme potřebovat i v dynamických datasetech, které si ukážeme už za malou chvilku.

abstract class DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
    /**
     * @var PHPUnit_Extensions_Database_DB_IDatabaseConnection
     */
    protected $connection = null;

    /**
     * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
     */
    protected function getConnection()
    {
        if ($this->connection === null) {
            $this->connection = $this->createDefaultDBConnection(
                new PDO('mysql:host=localhost;dbname=test', 'test', 'test')
            );
        }

        return $this->connection;
    }

    /**
     * @return PHPUnit_Extensions_Database_DataSet_IDataSet
     */
    protected function getDataset()
    {
        return $this->createFlatXMLDataSet(__DIR__ . "/dataset.xml");
    }

    protected function tearDown()
    {
        $this->connection->close();
        parent::tearDown();
    }
}

Dynamické datasety

Kromě statických datasetů, které jsme si minule ukázali, poskytuje DbUnit i dynamické, které můžeme vytvářet za běhu, nad aktuálním připojením k databázi. K čemu může být toto vhodné? Např. pokud chceme ověřovat výsledky dotazů, obsahy celých tabulek apod.

Database dataset

Tento dataset můžeme vytvořit dvěma způsoby: buď zavoláním metody createDataSet, kterou nabízí tzv. Connection API nebo přímo – vytvořením instance třídy PHPUnit_Extensions_Databa­se_DB_DataSet, které jako parametr konstruktoru předáme instanci Connection API.

Metoda createDataSet obsahuje jeden nepovinný parametr – pole se seznamem tabulek, které chceme do datasetu zahrnout. Defaultně jsou zahrnuty všechny, tímto parametrem dataset pouze omezujeme.

class DatabaseDatasetTest extends DatabaseTestCase
{
    public function testDatabaseDataset()
    {
        $expectedDataSet = $this->createFlatXMLDataSet(
            __DIR__ . "/databaseDataset.xml");
        $dbDataSet = $this->getConnection()->createDataSet();

        $this->assertDataSetsEqual($expectedDataSet, $dbDataSet);
    }

    public function testFilteredDatabaseDataset()
    {
        $expectedDataSet = $this->createFlatXMLDataSet(
            __DIR__ . "/databaseDataset.xml");
        $dbDataSet = $this->getConnection()->createDataSet(array("product"));

        $this->assertDataSetsEqual($expectedDataSet, $dbDataSet);
    }
}

Tento příklad nedělá nic světoborného. V prvním případě pouze ověřuje, zda obsah databáze (naplněný v rámci přípravy fixture) skutečně odpovídá obsahu datasetu, definovaného v souboru dataset.xml. Ve druhém případě to samé, jen s tím rozdílem, že dataset omezíme na tabulku product.

Query table dataset

Query table dataset je podobný předchozímu, jen s tím rozdílem, že jej můžeme plnit SQL dotazem. Využití nalézá třeba tam, kde chceme ověřovat výsledek dotazu proti námi definovanému datasetu. Vytvořit jej můžeme opět dvěma způsoby – buď pomocí metody createQueryTable nad Connection API nebo vytvořením instance třídy PHPUnit_Extensions_Databa­se_DataSet_QueryTable. Metoda createQueryTable přijímá dva parametry – název výsledku a SQL dotaz.

class QueryTableDatasetTest extends DatabaseTestCase
{
    public function testQueryTableDataset()
    {
        $queryTableDataset = $this->getConnection()->createQueryTable(
            "product", "SELECT * FROM product WHERE id > 1");

        $expectedDataSet = $this->createFlatXMLDataSet(
            __DIR__ . "/queryResultDataset.xml")->getTable("product");

        $this->assertTablesEqual($expectedDataSet, $queryTableDataset);
    }
}

Query dataset

Poslední z dynamických datasetů. Lze si jej představit jako rozšířenou verzi předchozího – není omezen jen na jednu tabulku, do tohoto datasetu můžeme přidávat hned několik výsledků SQL dotazů.

class QueryDatasetTest extends DatabaseTestCase
{
    public function testQueryDataset()
    {
        $queryDataset = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this->getConnection());
        $queryDataset->addTable("product", "SELECT * FROM product WHERE id > 1");
        // ... more SQL queries ...

        $expectedDataSet = $this->createFlatXMLDataSet(
            __DIR__ . "/queryResultDataset.xml");

        $this->assertDataSetsEqual($expectedDataSet, $queryDataset);
    }
}

Nové asserty

Rozšíření DbUnit přináší také další čtyři asserty, které můžeme použít.

assertTablesEqual

assertTablesEqual(PHPUnit_Extensions_Database_DataSet_ITable $expected, PHPUnit_Extensions_Database_DataSet_ITable $actual, $message = '')

Jak už název napovídá, assert ověřuje, zda se očekávaný obsah tabulky shoduje s aktuálním. Příklad použití už jsme viděli v ukázce Query table dataset.

assertDataSetsEqual

assertDataSetsEqual(PHPUnit_Extensions_Database_DataSet_IDataSet $expected, PHPUnit_Extensions_Database_DataSet_IDataSet $actual, $message = '')

Ověřuje shodu dvou celých datasetů. Příklad použití už jsme také viděli – viz ukázky Database dataset a Query dataset.

assertTableRowCount

assertTableRowCount($tableName, $expected, $message = '')

Jednoduchý assert ověřující, zda počet řádků v tabulce odpovídá očekávanému počtu. U tohoto assertu pozor na verzi rozšíření DbUnit, v aktuální verzi je chyba! Viz issue: https://github.com/se­bastianbergmann/dbunit/pu­ll/78.

class AssertTableRowCountTest extends DatabaseDatasetTest
{
    public function testAssertTableRowCount()
    {
        $this->assertTableRowCount("product", 3);
    }
}

assertTableContains

assertTableContains(array $expectedRow, PHPUnit_Extensions_Database_DataSet_ITable $table, $message = '')

Poslední z nových assertů – ověřuje existenci řádku v tabulce. Hledaný řádek definujeme pomocí pole.

class AssertTableContainsTest extends DatabaseTestCase
{
    public function testAssertTableContains()
    {
        $expected = array(
            "id" => "1",
            "name" => "Test product 1",
            "price" => "123");

        $this->assertTableContains(
            $expected,
            $this->getConnection()->createDataSet()->getTable("product"));
    }
}

Příště

Jako obvykle, všechny zdrojové kódy naleznete na Githubu, můžete si tak vše vyzkoušet. Dnešní díl je kratší než bývá zvykem, příště se podíváme na další velkou kapitolu frameworku PHPUnit, a tou bude XML konfigurace a CLI parametry, kterými můžeme řídit běh testů.

Komentáře

Odebírat
Upozornit na
guest
0 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
Zobrazit všechny komentáře

Strategie a AI jako klíč. Do Prahy přijely špičky technologického světa

WebExpo 2025 ukázalo, jak se tvoří budoucnost. Třídenní technologická konference WebExpo 2025 přivedla do Prahy světové i české experty, kteří nabídli inspiraci napříč obory. Hlavním tématem byla propojenost disciplín, význam AI a potřeba otevřenosti vůči novým výzvám – včetně podpory legální imigrace. Ukázalo se, že inovace vznikají nejen v Silicon Valley, ale i tam, kde se nebojíme myslet jinak.

Přístupnost není jen o splnění norem: nový pohled na inkluzivní design

Přístupnost a inkluze možná nepatří mezi nejžhavější témata digitálního světa – dokud o nich nezačne mluvit Vitaly Friedman. Na WebExpo 2024 předvedl, že inkluzivní design není jen o splněných checkboxech, ale hlavně o lidech. S energií sobě vlastní obrátil zažité přístupy naruby a ukázal, že skutečně přístupný web je nejen možný, ale i nezbytný.

Efektivnější vývoj UI nebo API: Co si odnést z WebExpo 2025?

Různé
Komentáře: 0
Jak snadno implementovat moderní uživatelské rozhraní? Které funkce brzdí rychlost vašeho webu? A kdy raději sami přibrzdit, abychom využitím AI nepřekročili etické principy? Debatu aktuálních dev témat rozdmýchá sedmnáctý ročník technologické konference WebExpo, která proběhne v Praze od 28. do 30. května. Který talk či workshop si rozhodně nenechat ujít? Toto je náš redakční výběr z vývojářských hroznů.