Skriva enhetstester med PHPUnit, del 3: XML-konfiguration
I de tidigare inläggen i den här serien har jag tagit upp följande två ämnen:
- Att skriva enhetstester med PHPUnit, del 1: Konfigurationen. En guide för att komma igång med att skriva PHPUnit-tester genom att använda en grundläggande cache och använda ramverkets setUp-metod.
- Att skriva enhetstester med PHPUnit, del 2: The Tear Down. En handledning om hur man skriver enhetstester som korrekt utnyttjar installations- och nedtagningsmetoderna för PHPUnit.
Vart och ett av ovanstående är tänkt att ge en primer för hur man kommer igång med att skriva mycket grundläggande enhetstester. Saker och ting kan bli mer komplexa, särskilt när en applikation eller ett projekt växer (men det är alltid sant, eller hur?).
Men för att se till att man är förberedd på det finns det en sista komponent i enhetstestning som jag tror att vi bör fokusera på och det är att förstå PHPUnit XML Configuration File (som du kanske har sett i andra projekt som phpunit.xml).
PHPUnit XML-konfiguration
Så i det här inlägget ska jag ställa in ett enkelt projekt som använder PHPUnit, skriver några tester som de vi redan har sett och använder en konfigurationsfil för att automatisera testning.
Dessutom ska jag göra vad jag kan för att på bästa sätt förklara de nödvändiga delarna av konfigurationsfilen så att du kan inkludera en i ditt nästa projekt.
1 Stubba ut filerna
Innan du börjar skriva testbar kod är det viktigt att veta vilka filer som kommer att behövas för att få processen att fungera.
Följande är, mer eller mindre, hur vi organiserar saker från början av ett projekt:
- en katalog för tester,
- filen phpunit.xml _
Så småningom kommer du också att se:
- filerna som utgör projektet,
- testerna som verifierar nämnda filer.
Men nu ska vi ta en titt på XML-konfigurationsfilen och sedan försöka köra PHPUnit automatiskt utan några andra parametrar.
2 Grunderna för konfigurationsfilen
Låt oss först titta på den grundläggande konfigurationsfilen:
<?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>
Låt oss nu förstå exakt vad vi tittar på (annat än enkel XML).
- phpunit. Den överordnade noden gör det vanliga jobbet med att definiera schemat för XML-filen, men det finns några andra komponenter som vi är angelägna om:
- backupGlobals. Detta är faktiskt relaterat till en anteckning som vi kan göra i vår källkod. Globaler är något vi bör försöka undvika i objektorienterad programmering, men om du väljer att använda en eller behöver använda en, kommer detta att berätta för PHPUnit att hantera de värden som de globala variablerna upprätthåller (och ger dig möjlighet att återställa dem). Jag lämnar i allmänhet detta som det är.
- bootstrap. Detta är valfritt, men om du väljer att inkludera andra filer i dina tester (som att ta in ett hånbibliotek, en del av WordPress eller ett bibliotek från tredje part), så kommer detta att vara allt du behöver för att definiera platsen för skriptet som måste Kör. Att håna och ta in WordPress ligger utanför omfattningen av det här inlägget men det är något vi troligen kommer att titta på i framtiden eftersom det är användbart när man testar plugins. För tillfället kommer jag att inkludera en enkel autoloader som i princip lägger till alla filer i roten av projektkatalogen. Den fullständiga källan till det kommer att delas senare i detta inlägg.
- färger. Om du vill att konsolen ska skriva ut en rapport över dina tester och göra det med färger (för att lättare kunna identifiera varningar, meddelanden, fel och så vidare), ställ sedan in detta på sant.
- Följande är alla booleska värden. Jag rekommenderar att ställa in dem till sanna för de mest aggressiva rapporterna som möjligt. På så sätt kommer du inte undan med att bara låta meddelanden eller varningar glida igenom samtidigt som du bara oroar dig för fel. Detta är mer en övning i kodkvalitet än något annat.
- convertErrorsToExceptions
- convertNoticesToExceptions
- convertWarningsToExceptions
- testsviter består av samlingar av tester. Eftersom ett givet projekt kan ha flera tester, är det viktigt att se till att du ger varje svit ett unikt namn och refererar till den rätta sökvägen till gruppen av tester. För vårt exempel kommer vi bara att ha en enda testsvit och den finns i testkatalogen.
- loggning är en funktion som kan vara så enkel som att skriva ut data i konsolen eller använda ett tredjepartsbibliotek (som Clover) för att generera rapporter som hjälper till med kontinuerlig integration. Eftersom jag ännu inte har diskuterat det senare i något av mina tidigare inlägg, kommer vi att hålla fast vid konsolen som vår huvudsakliga utmatningsmetod. Således har vi php ://stdout som vår enda loggningsutgång.
Med allt detta sagt har vår XML-fil allt som PHPUnit behöver för att köras utan några andra parametrar.
Kom dock ihåg att innan du fortsätter genom resten av den här artikeln, antar jag att du globalt har installerat PHPUnit på ditt system med hjälp av Composer. Om inte, läs den här artikeln eftersom den ger dig instruktioner om hur du gör det.
När du är klar kan du verifiera att PHPUnit är installerat genom att ange följande kommando i din terminal:
$ which phpunit
Och du bör se något i stil med följande:
Om du ser något liknande ovan, kan du köra PHPUnit var som helst från ditt system.
3 Bootstrap-filen
Innan vi går vidare, låt oss skriva en grundläggande bootstrap-fil. Vi kallar det bootstrap.php och släpper det i vår testkatalog. Det kommer att innehålla följande:
<?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;
}
}
Det här är en enkel "autoloader" (som jag tveksamt kallar det så med tanke på att det bara itererar igenom filer och kräver dem, men det fungerar för våra syften).
Låt oss nu ställa in ett grundläggande test.
4 Ett grundläggande, underkänd test
Om du läser något om testdriven utveckling kommer du sannolikt att få höra om en röd-grön-upprepa cykel. Det finns mycket att säga om det och jag rekommenderar att du läser på det, men det är inte syftet med det här inlägget.
Istället är vi mer fokuserade på att faktiskt skriva tester som matchar det vi behöver göra, eller hur? Så med det sagt, låt oss göra följande:
- skapa en katalog där du kommer att ha några grundläggande PHP-filer som vi testar,
- i roten av katalogen, skapa även phpunit.xml och fyll i den med koden som delas tidigare i det här inlägget
- skapa en testkatalog där vi placerar våra tester.
Nu, från terminalen, byt katalog till projektets katalog (som visserligen saknas för tillfället) och kör sedan helt enkelt php unit:
$ phpunit
Förutsatt att allt är korrekt inställt bör du se något i stil med detta:
Eftersom vi inte har någon kod och inga tester, kommer vi naturligtvis att se utdata ovan, eller hur? Så låt oss skriva ett enda test som kommer att köras (och misslyckas) eftersom det inte finns någon kod som det faktiskt kan testa.
Skapa först en fil som heter AcmeCacheTest.php i testkatalogen. Och låt oss få det att göra något enkelt som att instansiera ett cacheobjekt som vi så småningom kommer att skapa.
<?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);
}
}
Innan du kör testet, lägg märke till att vi:
- Se till att använda PHPUnitFrameworkTestCase
- Och låt vår klass utöka TestCase
Detta är en del av det som gör det så enkelt att använda PHPUnit. När det är gjort, kör följande kod från roten av ditt projekt:
$ phpunit
Efter det bör du se följande:
Observera att detta kommer att ge ett underkänt test och det kommer att berätta var problemet hittades, filen och raden.
För att fixa detta måste vi skriva en klass:
<?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 Några grundläggande, godkända test
Det grundläggande godkända testet (som kommer att baseras på tidigare kod) kommer att innehålla följande:
- en namnavgränsad fil,
- kommer att representera en enkel cache,
- kommer automatiskt att laddas av PHPUnit med hjälp av filen bootstrap.php som delas ovan
- och kommer att ha en varaktighet inställd i sin konstruktor tillsammans med en setter och getter för värdet
Låt oss först testa att vi kan ställa in klassen och att den inte är null. Detta är lite av ett onödigt påstående eftersom vi vet att vi kommer att ha en klass korrekt instansierad, men det får oss in i spåret med att skriva tester:
<?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);
}
}
Och kör testet:
Låt oss sedan verifiera att standardvärdet för cachen är inställt:
<?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());
}
}
Som med föregående steg, kör testerna, och du bör nu se två godkända test:
Slutligen, låt oss testa för att se om vi lyckas ändra värdet:
<?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());
}
}
Och de tre sista godkända testerna:
Och där har du det:
- en PHPUnit XML-fil,
- en enkel bootstrap,
- en enda klass med namnavstånd,
- enhetstester för varje metod i klassen
Visst, det är enkelt, men detta lägger grunden för så mycket mer än vad många människor redan gör med sina tester.
Dessutom ger det dig något att bygga på när dina testkotletter växer sig starkare.
Finns det mer? (Alltid rätt?)
Slutligen, om du är sugen på att verkligen dyka in i konfigurationsfilen, kan du läsa manualens djupgående förklaring av den.
Observera dock att allt som beskrivs ovan syftar till att vara det du behöver för att komma igång med att sätta upp din egen PHPUnit XML-konfigurationsfil.




