WordPress bővítmény- és téma-tesztelés PHPUnit-tel: gyakorlati útmutató WP-CLI scaffolddal
A WordPress-fejlesztés egyik legjobb befektetése az automatizált tesztelés. Nem azért, mert minden bug eltűnik tőle, hanem mert sokkal korábban veszed észre a hibákat, és nem a felhasználóid fognak szembesülni velük élesben. A WordPress ökoszisztémában a biztonsági problémák jelentős része bővítményekhez köthető; egy stabil tesztkészlet rengeteget segít abban, hogy kisebb eséllyel csússzon be regresszió vagy váratlan mellékhatás.
Miért érdemes komolyan venni a tesztelést?
Az automatizált tesztek (különösen a PHPUnit-alapú tesztek) több szinten is megtérülnek:
- Hibák korai felismerése: nem a release napján derül ki, hogy egy edge case szétveri a kódot.
- Regressziók megelőzése: ha egyszer már kijavítottál egy bugot, legyen róla teszt, hogy ne jöjjön vissza.
- Jobb kódminőség: a tesztelhető kód jellemzően tisztább, jobban tagolt.
- Magabiztosabb refaktorálás: ha a tesztkészlet zöld, sokkal kevésbé félsz belenyúlni a kódba.
Előfeltételek: mire lesz szükséged?
A WordPress PHPUnit tesztkörnyezethez pár alap összetevő kell. Ezeket érdemes előre összerakni, mert a scaffold parancsok ugyan generálnak fájlokat, de a futtatáshoz a környezetednek is készen kell állnia.
- PHP 8.0+ (a PHPUnit 10 megköveteli)
- Composer (függőségkezeléshez)
- WP-CLI (WordPress parancssori eszköz)
- MySQL/MariaDB (külön teszt adatbázishoz)
- Subversion (svn) (a WordPress teszt fájlok letöltéséhez)
WP-CLI telepítése (gyors módszer)
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
PHPUnit felvétele Composer-rel (ajánlott)
A PHPUnit-et érdemes projekt-szinten, dev függőségként felvenni. WordPress projektekben gyakori a kompatibilitási réteg használata is, erre való a yoast/phpunit-polyfills csomag (különböző PHPUnit/PHP verziók közti eltérések áthidalására).
{
"require-dev": {
"phpunit/phpunit": "^10.0",
"yoast/phpunit-polyfills": "^2.0"
}
}
Bővítmény tesztek generálása WP-CLI scaffolddal
A WP-CLI scaffold parancsai pont arra jók, hogy ne kézzel kelljen összeraknod a WordPress tesztkörnyezet tipikus fájljait. Bővítményhez a kiindulópont a wp scaffold plugin-tests.
wp scaffold plugin-tests my-plugin
Milyen fájlokat kapsz a generálás után?
A parancs létrehozza a PHPUnit futtatásához és a WordPress tesztkörnyezet bootstrappeléséhez szükséges alapokat. Tipikusan ezek jelennek meg a projektedben:
phpunit.xml.dist– a PHPUnit konfigurációja (suite-ok, bootstrap, beállítások).bin/install-wp-tests.sh– telepítő script a WordPress tesztkörnyezethez.tests/bootstrap.php– a tesztek inicializálása, WordPress betöltése a teszt futásához.tests/test-sample.php– egy minta teszt, amivel gyorsan ellenőrizheted, hogy működik-e a setup..phpcs.xml.dist– PHP CodeSniffer szabályok (kódszabvány ellenőrzéshez)..circleci/config.yml– CI konfiguráció (alapértelmezésben CircleCI-hez).
CI provider kiválasztása a scaffoldnál
Ha nem CircleCI-t használsz, a scaffold képes más CI szolgáltatókhoz is konfigurációt generálni. A --ci kapcsolóval tudod megadni, milyen pipeline formátumot szeretnél.
# GitHub Actions
wp scaffold plugin-tests my-plugin --ci=github
# GitLab CI
wp scaffold plugin-tests my-plugin --ci=gitlab
# CircleCI (alapértelmezett)
wp scaffold plugin-tests my-plugin --ci=circle
# Bitbucket Pipelines
wp scaffold plugin-tests my-plugin --ci=bitbucket
Tesztkörnyezet felhúzása az install-wp-tests.sh script segítségével
A scaffold által generált bin/install-wp-tests.sh a kulcs: ez rakja össze a WordPress-hez szükséges teszt infrastruktúrát. A szokásos munkafolyamat az, hogy belépsz a bővítmény könyvtárába, majd lefuttatod a scriptet a megfelelő paraméterekkel.
cd wp-content/plugins/my-plugin
bash bin/install-wp-tests.sh wordpress_test root password localhost latest
Mit jelentenek a paraméterek?
wordpress_test– a teszt adatbázis neve (minden adat törlődni fog ebben az adatbázisban).root– MySQL felhasználó.password– a MySQL felhasználó jelszava.localhost– az adatbázis szerver címe.latest– a WordPress verziója (adhatsz konkrétat is, például:6.9).
Mit csinál a script a háttérben?
A script lényegében három nagy lépést automatizál:
- Létrehozza (vagy újrahúzza) a teszt adatbázist.
- Letölti a WordPress-t a
/tmpmappába. - Telepíti a WordPress teszt eszközöket (a PHPUnit-alapú WordPress teszt suite-hoz szükséges fájlokat).
Téma (theme) tesztek scaffoldolása
Témáknál ugyanez a logika, csak a scaffold parancs neve más: wp scaffold theme-tests. A CI konfigurációt itt is kérheted például GitHub Actions-hoz.
wp scaffold theme-tests my-theme --ci=github
A különbség a bootstrappelésnél lesz fontos: a tests/bootstrap.php témánál jellemzően gondoskodik arról, hogy a téma aktív legyen a tesztek futása közben.
Tesztek futtatása: a leggyakoribb parancsok
Ha egyszer megvan a környezet (adatbázis + WP teszt suite + függőségek), a futtatás egyszerű: a projekt könyvtárából elindítod a PHPUnit-et.
cd wp-content/plugins/my-plugin
phpunit
Ha minden rendben, valami ilyesmit látsz:
OK (1 test, 1 assertion)
Konkrét tesztek célzott futtatása
Nagyobb projekteknél sok időt spórolsz, ha nem mindig a teljes suite fut. A PHPUnit erre több opciót is ad:
# Egy teszt osztály
phpunit --filter TestClassName
# Egy teszt metódus
phpunit --filter test_method_name
# Csoport alapján
phpunit --group slow
Tesztek írása WordPress-hez: stabil alapok
Egy alap teszt osztály felépítése
WordPress-ben a klasszikus PHPUnit tesztek gyakran WP_UnitTestCase-ből származnak. A set_up() és tear_down() metódusokkal tudod rendbe tenni a környezetet tesztenként.
<?php
class Test_My_Plugin extends WP_UnitTestCase {
public function set_up() {
parent::set_up();
// Teszt előkészítés
}
public function tear_down() {
// Takarítás
parent::tear_down();
}
public function test_plugin_is_active() {
$this->assertTrue( is_plugin_active( 'my-plugin/my-plugin.php' ) );
}
}
AAA minta: Arrange, Act, Assert
A jól olvasható tesztek egyik bevált receptje az AAA (Arrange, Act, Assert): előkészítesz mindent, végrehajtod a műveletet, majd ellenőrzöd az eredményt. Ettől a teszt nem csak működik, de később is gyorsan érthető marad.
public function test_coupon_applied_to_order() {
// Arrange - előkészítés
$order = $this->factory->order->create();
$coupon = $this->create_coupon( 'SAVE10', 10 );
// Act - végrehajtás
$result = apply_coupon_to_order( $order, $coupon );
// Assert - ellenőrzés
$this->assertTrue( $result );
$this->assertEquals( 10, get_order_discount( $order ) );
}
Beszédes tesztnevek: konvenció, ami tényleg segít
A tesztnevek legyenek önleírók. Ha egy CI futás elhasal, a teszt neve lesz az első, amit megnézel – és sokszor már abból tudni akarod, mi romlott el.
// Jó
public function test_user_can_subscribe_to_newsletter() {}
public function test_invalid_email_returns_error() {}
public function test_duplicate_subscription_is_prevented() {}
// Rossz
public function test_1() {}
public function test_subscription() {}
WordPress Test Factory: gyors adatkészítés tesztekhez
A WordPress teszt keretrendszer egyik legerősebb része a beépített factory rendszer: nagyon gyorsan tudsz felhasználót, bejegyzést, taxonómiát stb. generálni tesztadatnak. Így nem kézzel kell SQL-t vagy hosszú setupot írnod.
// Post létrehozása
$post_id = $this->factory->post->create([
'post_title' => 'Test Post',
'post_status' => 'publish'
]);
// User létrehozása
$user_id = $this->factory->user->create([
'role' => 'administrator'
]);
// Több elem létrehozása
$post_ids = $this->factory->post->create_many( 5 );
// Term létrehozása
$term_id = $this->factory->term->create([
'taxonomy' => 'category',
'name' => 'Test Category'
]);
Külső HTTP hívások tesztelése: mockolás a pre_http_request filterrel
Ha a kódod külső API-t hív, tesztben nem szerencsés valós hálózati kérést futtatni: lassú, törékeny, és függ a külső szolgáltatótól. WordPress-ben erre kézenfekvő a pre_http_request filter (hook), amivel a HTTP réteg elé tudsz vágni és visszaadhatsz egy „mintha” választ.
public function test_api_call_returns_expected_data() {
// Mock beállítása
add_filter( 'pre_http_request', function( $preempt, $args, $url ) {
if ( strpos( $url, 'api.example.com' ) !== false ) {
return [
'response' => [ 'code' => 200 ],
'body' => json_encode( [ 'status' => 'success' ] )
];
}
return $preempt;
}, 10, 3 );
// Teszt végrehajtása
$result = my_plugin_fetch_data();
$this->assertEquals( 'success', $result['status'] );
}
Best practice-ek, amik hosszú távon megmentenek
1) Ne implementációt tesztelj, hanem viselkedést
Gyakori csapda, hogy egy belső megvalósítási részletre írsz tesztet (például transients, belső cache kulcsok, konkrét tárolási stratégia). Ezek refaktoráláskor változhatnak úgy, hogy közben a funkció viselkedése helyes marad – te mégis elhasaló teszteket kapsz.
// Rossz - transient implementációs részlet
public function test_data_is_cached() {
fetch_data();
$this->assertNotFalse( get_transient( 'my_cache_key' ) );
}
// Jó - viselkedés tesztelése
public function test_second_call_uses_cache() {
$start = microtime( true );
fetch_data();
fetch_data(); // Második hívás gyorsabb kell legyen
$duration = microtime( true ) - $start;
$this->assertLessThan( 0.1, $duration );
}
2) Tartsd izoláltan a teszteket
A WordPress Test Library alapból segít abban, hogy minden teszt után visszaálljon az adatbázis állapota. Ezt könnyű elrontani, ha tesztek között megosztott állapotra építesz (például statikus property-ben tárolt ID-kra). Az ilyen tesztek sorrendfüggők lesznek, és CI-ben jönnek elő a legidegesítőbb, nehezen reprodukálható hibák.
// Rossz
private static $shared_post_id;
public function test_one() {
self::$shared_post_id = $this->factory->post->create();
}
public function test_two() {
// Ez a teszt függ test_one-tól
$post = get_post( self::$shared_post_id );
}
// Jó
public function test_one() {
$post_id = $this->factory->post->create();
// Minden teszt önálló
}
3) Data provider-ek: több eset, kevesebb duplikáció
Ha ugyanazt a logikát több input-output kombinációval akarod lefedni (klasszikus példa: validáció), akkor a PHPUnit data provider-ei sokkal tisztábbá teszik a kódot.
/**
* @dataProvider email_validation_provider
*/
public function test_email_validation( $email, $expected ) {
$this->assertEquals( $expected, is_valid_email( $email ) );
}
public function email_validation_provider() {
return [
'valid email' => [ 'test@example.com', true ],
'missing @' => [ 'testexample.com', false ],
'missing domain' => [ 'test@', false ],
'empty string' => [ '', false ],
];
}
4) Teszt csoportok: gyors és lassú futások szétválasztása
Nem minden teszt egyforma: lesznek villámgyors unit tesztek és lassabb integrációs tesztek. A PHPUnit group annotációival ezt jól tudod kezelni.
/**
* @group slow
* @group integration
*/
public function test_slow_operation() {
// Lassú teszt
}
/**
* @group fast
* @group unit
*/
public function test_fast_calculation() {
// Gyors teszt
}
Futtatási példák:
# Csak gyors tesztek
phpunit --group fast
# Lassú tesztek kihagyása
phpunit --exclude-group slow
Minta GitHub Actions workflow PHPUnit-hez (MySQL service-szel)
Ha GitHub Actions-t használsz, érdemes a teszteket több PHP- és WordPress-verzióval is lefuttatni. Az alábbi példa MySQL 8.0 service-t indít, majd matrixban végigpróbálja a megadott verziókat.
name: PHPUnit Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress_test
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
strategy:
matrix:
php-version: ['8.1', '8.2', '8.3']
wordpress-version: ['6.8', '6.9', 'latest']
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: mysqli, intl, zip, gd
coverage: xdebug
- name: Install Composer dependencies
run: composer install --no-progress --prefer-dist
- name: Install WordPress test suite
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress-version }}
- name: Run PHPUnit
run: vendor/bin/phpunit --coverage-text
Összefoglalás: a teljes folyamat röviden
Ha WordPress bővítményt vagy témát fejlesztesz, a WP-CLI scaffold parancsokkal meglepően gyorsan eljutsz egy működő PHPUnit setupig:
- Scaffoldold a teszteket:
wp scaffold plugin-testsvagywp scaffold theme-tests. - Húzd fel a tesztkörnyezetet:
bash bin/install-wp-tests.sh ...(külön teszt adatbázissal!). - Futtasd a teszteket:
phpunit(vagy CI-benvendor/bin/phpunit).
A stabil tesztkészlet ismérvei: izolált tesztek, beszédes elnevezések, AAA szerkezet, és a viselkedés tesztelése implementációs részletek helyett. Ha ezt a néhány alapelvet követed, a tesztjeid nem akadályozni fognak, hanem gyorsítani a fejlesztést.
Hivatkozások / Források
Patai László
1999 óta foglalkozom nyílt forrású rendszerekkel, 2006 óta kimondottan WordPress-el. Szakterületem a nagy forgalmú weboldalak fejlesztése és üzemeltetése.
Összes bejegyzés