Ha valaha is láttál már egy bővítményt, ami lokálisan "működött", majd egy kisebb frissítés után csendben leállt... WordPress A 6.9.4-es verzióban a probléma ritkán egyetlen sorból ered. A reprodukálható tesztek hiányából, és különösen a tiszta logika és a WordPress integráció közötti szétválasztás hiányából fakad.
Amit építeni fogunk
Egy modern tesztkörnyezetet fogsz beállítani (2026 áprilisában) egy PHP 8.1+ és WordPress 6.9.4+ verziókkal kompatibilis WordPress bővítményhez, két szinttel:
- Egységtesztek (gyors): teszteld a PHP logikádat a WordPress betöltése nélkül.
- Integrációs tesztek (realisztikus): töltse be a WordPress-t, és validálja a hookokat, szerepköröket/képességeket, nonce-okat és adatbázis-interakciókat a következőn keresztül:
WP_UnitTestCase.
A végeredmény: egy minta plugin, a „BPCAB Demo” tesztelhető architektúrával (szolgáltatások + egyszerű DI), egy PHPUnit csomaggal és egy GitHub Actions folyamattal, amely teszteket futtat egy PHP/WP mátrixon.
A végén megtudod:
- Egy bővítmény felépítése, hogy a logika tesztelhető legyen WordPress nélkül.
- Telepítsd és konfiguráld megfelelően a WordPress tesztcsomagot a Composer segítségével.
- Írj megbízható, nem hibás teszteket (egység + integráció).
- Automatizálja a CI-végrehajtást mátrix és gyorsítótárak segítségével.
Gyors összefoglaló
- Elválunk domain (tiszta PHP) és infrastruktúra (WP, DB, REST, adminisztrációs hookok).
- A zeneszerző kezeli autoload és fejlesztési függőségek (
phpunit/phpunit). - Két PHPUnit csomag: egység (WP nélkül) és integráció (WP-vel).
- Az integrációs bootstrap a WordPress-t a következőn keresztül tölti be: WP tesztcsomag és konfigurálja a tesztadatbázist.
- A CI-n egy mátrixot hajtunk végre PHP 8.1/8.2/8.3 + WP 6.9.4 (és esetleg éjszakai (ha szeretsz veszélyesen élni).
Mikor kell használni ezt a megoldást
- Ön egy „üzletileg kritikus” bővítményt tart fenn (e-kereskedelem, tagság, SEO, űrlapok, szinkronizáció).
- Regressziókat tapasztalsz a WordPress/PHP frissítések során.
- Csapatként fejlődsz, és olyan PR-okat szeretnél, akik kevesebbszer hibáznak.
- Komplex hookokat használsz (prioritások, kumulatív szűrők, rövidkódok, REST).
- A befizetésre célzol WordPress.org És minimális szigorúságot szeretnél.
Mikor NEM szabad ezt a megoldást használni
- A „bővítményed” egy egyszerű, 15 soros kódrészlet, amit egy kódrészlet-bővítménybe illesztettek be (és még akkor is: egy egységteszt hasznos lehet, de a befektetés aránytalanul nagy).
- Egyetlen projekten dolgozol karbantartás nélkül (ami ritka a WordPressben, de létezik).
- Nem vagy hajlandó bevezetni a Composert: automatikus betöltés és fejlesztői függőségek nélkül csak időt pazarolsz a bütykölésre.
- Nincs elszigetelt környezeted (Docker/teszt adatbázis). Éles környezetben, biztonsági mentések nélkül tesztelve, láttam már ilyet, és rosszul végződött.
Mielőtt elkezdené (előfeltételek)
Verziók és környezet
- WordPress : 6.9.4 (cél) vagy újabb verzió.
- PHP : Minimum 8.1 (ajánlott), 8.2/8.3 OK.
- Összeállít : 2.x.
- MySQL / MariaDB : tesztelésre szánt adatbázis (pl.:
wp_tests).
Biztonsági mentés és elkülönítés
- Ne mutogass! soha a tesztkonfigurációt az éles adatbázisba.
- Ha lehetséges, hozzon létre egy korlátozott adatbázis-felhasználót tesztelési célokra.
- Dolgozz egy Git repóban: konfigurációs fájlokat és szkripteket fogsz kezelni.
Hasznos hivatalos források
- WP-CLI (fejlesztői források) (hasznos, de opcionális).
- @wordpress/scripts (ha JS-t is tesztelsz, a fő hatókörön kívül).
- PHPUnit dokumentáció.
- WordPress Core kézikönyv: PHPUnit.
- wordpress-fejlesztési adattár (a WP tesztcsomag forrása).
1. lépés: Tesztelhető bővítmény létrehozása (váz + automatikus betöltés)
Az igazi előny ebből adódik: ha a logikád névtelen visszahívásokban ragad, akkor a kódod helyett a "WordPress-t teszteled". Általában elkülönítem a következőket:
- src/Domain : tiszta logika (egységteszt).
- src/Infrastruktúra WordPress (hookok, opciók, REST, admin).
- src/Bővítmény : bootstrap és szolgáltatásregisztráció.
1) Hozd létre a bővítménymappát
Dans wp-content/plugins/, hozd létre:
bpcab-demo/bpcab-demo/bpcab-demo.phpbpcab-demo/src/bpcab-demo/tests/
2) Fő bővítményfájl
teremt wp-content/plugins/bpcab-demo/bpcab-demo.php :
<?php
/**
* Plugin Name: BPCAB Demo (Testable)
* Description: Plugin d'exemple pour tests unitaires + intégration WordPress.
* Version: 0.1.0
* Requires at least: 6.9
* Requires PHP: 8.1
*/
declare(strict_types=1);
if (!defined('ABSPATH')) {
exit;
}
// Autoload Composer (en dev, et aussi en prod si vous packez vendor/).
$autoload = __DIR__ . '/vendor/autoload.php';
if (file_exists($autoload)) {
require_once $autoload;
}
add_action('plugins_loaded', static function (): void {
// Bootstrap minimal. En vrai, je préfère une classe Plugin + container.
$plugin = new BpcabDemoPluginPlugin(__FILE__);
$plugin->boot();
});
3) Egy Plugin osztály + egy mini-konténer
teremt src/Plugin/Plugin.php :
<?php
declare(strict_types=1);
namespace BpcabDemoPlugin;
use BpcabDemoInfrastructureHooksHelloHook;
use BpcabDemoPluginContainerContainer;
final class Plugin
{
private string $pluginFile;
private Container $container;
public function __construct(string $pluginFile)
{
$this->pluginFile = $pluginFile;
$this->container = new Container();
}
public function boot(): void
{
// Enregistrement des services.
$this->container->set(HelloHook::class, function (): HelloHook {
return new HelloHook();
});
// Activation des intégrations WP.
$this->container->get(HelloHook::class)->register();
}
}
teremt src/Plugin/Container/Container.php :
<?php
declare(strict_types=1);
namespace BpcabDemoPluginContainer;
use RuntimeException;
final class Container
{
/** @var array<string, callable> */
private array $factories = [];
/** @var array<string, object> */
private array $instances = [];
/**
* @param callable():object $factory
*/
public function set(string $id, callable $factory): void
{
$this->factories[$id] = $factory;
}
public function get(string $id): object
{
if (isset($this->instances[$id])) {
return $this->instances[$id];
}
if (!isset($this->factories[$id])) {
throw new RuntimeException("Service introuvable: {$id}");
}
$instance = ($this->factories[$id])();
$this->instances[$id] = $instance;
return $instance;
}
}
4) Példa a tiszta logikára + egy WP hook
teremt src/Domain/Greeting.php :
<?php
declare(strict_types=1);
namespace BpcabDemoDomain;
final class Greeting
{
public function message(string $name): string
{
$name = trim($name);
if ($name === '') {
return 'Bonjour !';
}
// Cas réel : éviter les espaces multiples, et limiter la taille.
$name = preg_replace('/s+/', ' ', $name) ?? $name;
$name = mb_substr($name, 0, 60);
return "Bonjour {$name} !";
}
}
teremt src/Infrastructure/Hooks/HelloHook.php :
<?php
declare(strict_types=1);
namespace BpcabDemoInfrastructureHooks;
use BpcabDemoDomainGreeting;
final class HelloHook
{
public function register(): void
{
add_shortcode('bpcab_hello', [$this, 'shortcode']);
}
/**
* @param array<string,mixed> $atts
*/
public function shortcode(array $atts = []): string
{
$atts = shortcode_atts(
[
'name' => '',
],
$atts,
'bpcab_hello'
);
$greeting = new Greeting();
// Sécurité : sortie échappée.
return esc_html($greeting->message((string) $atts['name']));
}
}
Várható eredmény
Aktiválja a bővítményt a Extensions → Telepített bővítményekEgy oldalon add hozzá:
[bpcab_hello name="Marie Curie"]
Látnod kell a „Hello Marie Curie!”-t.
2. lépés: Telepítse a PHPUnit-ot + WordPress tesztcsomagot (Composer)
WordPressen a klasszikus zavarodottság adódik: „Telepítettem a PHPUnitot, így tesztelhetek.” Nem. Az integrációs teszteléshez a WP Test Suite-ra is szükség van (a fájlok includes/bootstrap.phpgyárak stb.).
1) Inicializálja a zeneszerzőt
A bővítmény mappájában:
cd wp-content/plugins/bpcab-demo
composer init
Azt javaslom, hogy adj meg egy csomagnév típust vendor/bpcab-demoés meghatározni src/ mint forrás.
2) PHPUnit és PSR-4 automatikus betöltés hozzáadása
Létrehozás/szerkesztés composer.json :
{
"name": "vendor/bpcab-demo",
"type": "wordpress-plugin",
"require": {
"php": ">=8.1"
},
"require-dev": {
"phpunit/phpunit": "^11.0"
},
"autoload": {
"psr-4": {
"BpcabDemo\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"BpcabDemo\Tests\": "tests/"
}
},
"scripts": {
"test:unit": "phpunit -c phpunit.unit.xml",
"test:integration": "phpunit -c phpunit.integration.xml"
}
}
Akkor:
composer install
composer dump-autoload
3) Szerezd meg a WordPress tesztcsomagot
Több módszered is van. 2026-ban a legegyszerűbb marad:
- klón wordpress-fejlesztés valahol a gépeden,
- használja az ő fájlját
tests/phpunitutólagos tesztként.
Példa (átdolgozandó):
mkdir -p ~/wp-tests
cd ~/wp-tests
git clone --depth=1 https://github.com/WordPress/wordpress-develop.git
Ezután a következőket kapod:
~/wp-tests/wordpress-develop/tests/phpunit~/wp-tests/wordpress-develop/src(a központi munkacsomag „fejleszthető”)
A PHPUnit központi oldali megközelítésének hivatalos forrása: Alapvető kézikönyv: Automatizált tesztelés / PHPUnit.
3. lépés: Írd meg a teszt bootstrap-et és izoláld a környezetet
Megyünk teremt két PHPUnit konfiguráció:
- egység : nincs WordPress, gyors, nincs adatbázis.
- integráció : WordPress betöltés + teszt adatbázis.
1) PHPUnit konfiguráció: „egység”
teremt phpunit.unit.xml a bővítmény gyökerében:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="tests/bootstrap-unit.php"
colors="true"
failOnRisky="true"
failOnWarning="true"
cacheDirectory=".phpunit.cache/unit"
>
<testsuites>
<testsuite name="unit">
<directory suffix="Test.php">tests/unit</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
</php>
</phpunit>
teremt tests/bootstrap-unit.php :
<?php
declare(strict_types=1);
// Bootstrap minimal pour tests unitaires : autoload uniquement.
$autoload = dirname(__DIR__) . '/vendor/autoload.php';
if (!file_exists($autoload)) {
fwrite(STDERR, "Autoload introuvable. Lancez 'composer install'.n");
exit(1);
}
require_once $autoload;
2) PHPUnit „integráció” konfigurálása
teremt phpunit.integration.xml :
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
bootstrap="tests/bootstrap-integration.php"
colors="true"
failOnRisky="true"
failOnWarning="true"
cacheDirectory=".phpunit.cache/integration"
>
<testsuites>
<testsuite name="integration">
<directory suffix="Test.php">tests/integration</directory>
</testsuite>
</testsuites>
<php>
<ini name="error_reporting" value="-1"/>
<!-- Paramètres DB : ne mettez jamais la prod ici -->
<env name="WP_TESTS_DB_NAME" value="wp_tests"/>
<env name="WP_TESTS_DB_USER" value="root"/>
<env name="WP_TESTS_DB_PASS" value=""/>
<env name="WP_TESTS_DB_HOST" value="127.0.0.1"/>
<!-- Chemins vers wordpress-develop (à adapter à votre machine) -->
<env name="WP_DEVELOP_DIR" value="/home/vous/wp-tests/wordpress-develop"/>
</php>
</phpunit>
teremt tests/bootstrap-integration.php :
<?php
declare(strict_types=1);
/**
* Bootstrap d'intégration WordPress.
* Hypothèse : vous avez cloné wordpress-develop et indiqué WP_DEVELOP_DIR.
*/
$autoload = dirname(__DIR__) . '/vendor/autoload.php';
if (!file_exists($autoload)) {
fwrite(STDERR, "Autoload introuvable. Lancez 'composer install'.n");
exit(1);
}
require_once $autoload;
$developDir = getenv('WP_DEVELOP_DIR');
if (!$developDir) {
fwrite(STDERR, "WP_DEVELOP_DIR manquant. Configurez-le dans phpunit.integration.xml.n");
exit(1);
}
$testsDir = rtrim($developDir, '/\') . '/tests/phpunit';
if (!is_dir($testsDir)) {
fwrite(STDERR, "Dossier tests WordPress introuvable: {$testsDir}n");
exit(1);
}
// Variables attendues par la WP test suite.
$_tests_dir = $testsDir;
// Charge les fonctions utilitaires de la suite.
require_once $_tests_dir . '/includes/functions.php';
/**
* Charger le plugin avant que WordPress ne finisse son bootstrap de tests.
* C'est le point standard (muplugins_loaded) utilisé par la suite.
*/
tests_add_filter('muplugins_loaded', static function (): void {
require dirname(__DIR__) . '/bpcab-demo.php';
});
// Démarre WordPress pour les tests.
require_once $_tests_dir . '/includes/bootstrap.php';
Várható eredmény
Ebben a szakaszban a tesztek futtatása még mindig nem eredményez semmit (nincsenek tesztfájlok), de:
composer test:unit
legalább a PHPUnit-ot el kell indítani.
4. lépés: Írj valódi egységteszteket (WordPress betöltése nélkül)
Tesztelünk BpcabDemoDomainGreetingEz a teszt gyors, determinisztikus, és nem függ a WP magtól.
1) Hozd létre a mappát és a tesztet
teremt tests/unit/GreetingTest.php :
<?php
declare(strict_types=1);
namespace BpcabDemoTestsUnit;
use BpcabDemoDomainGreeting;
use PHPUnitFrameworkTestCase;
final class GreetingTest extends TestCase
{
public function testMessageSansNomRetourneUneFormeCourte(): void
{
$greeting = new Greeting();
$this->assertSame('Bonjour !', $greeting->message(''));
$this->assertSame('Bonjour !', $greeting->message(' '));
}
public function testMessageNormaliseLesEspaces(): void
{
$greeting = new Greeting();
$this->assertSame('Bonjour Ada Lovelace !', $greeting->message('Ada Lovelace'));
}
public function testMessageLimiteLaLongueurPourEviterDesSortiesAbsurdes(): void
{
$greeting = new Greeting();
$name = str_repeat('A', 1000);
$result = $greeting->message($name);
$this->assertStringStartsWith('Bonjour ', $result);
$this->assertStringEndsWith(' !', $result);
// "Bonjour " (8) + 60 + " !" (2) = 70
$this->assertSame(70, mb_strlen($result));
}
}
2) Futtassa az egységteszteket
composer test:unit
Várható eredmény
Egy zöld sorozatnak kell megjelennie. Ha olyan hibát kapsz, mint például a „Class not found” (Osztály nem található), az szinte mindig a következő:
- helytelen PSR-4 automatikus betöltés
composer.json, - elfelejtetted
composer dump-autoload, - Rossz mappába tetted a fájlt.
5. lépés: WordPress integrációs tesztek (WP_UnitTestCase)
Most ellenőrizzük, hogy a rövidkód megfelelően van-e regisztrálva, és hogy a megjelenítés helyes-e. Ezen a ponton betöltjük a WordPress-t, így lassabb lesz, de elkapja a "valódi" regressziókat.
1) Hozz létre egy integrációs tesztet
teremt tests/integration/ShortcodeHelloTest.php :
<?php
declare(strict_types=1);
namespace BpcabDemoTestsIntegration;
use WP_UnitTestCase;
final class ShortcodeHelloTest extends WP_UnitTestCase
{
public function testShortcodeEstEnregistre(): void
{
// Le plugin est chargé via bootstrap-integration.php.
global $shortcode_tags;
$this->assertIsArray($shortcode_tags);
$this->assertArrayHasKey('bpcab_hello', $shortcode_tags);
}
public function testShortcodeRendLeTexteAttendu(): void
{
$html = do_shortcode('[bpcab_hello name="Marie Curie"]');
// esc_html() est appliqué, donc pas de HTML.
$this->assertSame('Bonjour Marie Curie !', $html);
}
}
2) Futtassa az integrációs teszteket
composer test:integration
Várható eredmény
Ha a tesztadatbázis elérhető, és WP_DEVELOP_DIR helyes, akkor egy zöld sorozatot kapsz.
Ha a „Hiba az adatbázis-kapcsolat létrehozásakor” hibaüzenetet látja, ne próbálja meg véletlenszerűen javítani. Először ellenőrizze a következőket:
- bázis
wp_testslétezik, - Az adatbázis-felhasználó rendelkezik a jogokkal,
- nem tetted
localhostmiközben a MySQL figyeli127.0.0.1(vagy fordítva, a konfigurációtól függően).
6. lépés: Horgok, szűrők, képességek és nonce-ok tesztelése
Azok a tesztek, amelyek a legtöbb hibát észlelik éles környezetben: azok, amelyek ellenőrzik, hogy a hookokat a megfelelő helyre, a megfelelő prioritással helyezted-e el, és hogy a biztonság (nonce/capabilities) tiszteletben van-e tartva.
1) Biztonságos adminisztrátori művelet hozzáadása (példa)
Hozzáadunk egy nagyon egyszerű adminisztrátori műveletvégpontot: frissít egy opciót, de csak adminisztrátorok számára és nonce értékkel.
teremt src/Infrastructure/Admin/SettingsAction.php :
<?php
declare(strict_types=1);
namespace BpcabDemoInfrastructureAdmin;
final class SettingsAction
{
public const NONCE_ACTION = 'bpcab_demo_save';
public const OPTION_KEY = 'bpcab_demo_enabled';
public function register(): void
{
add_action('admin_post_bpcab_demo_save', [$this, 'handle']);
}
public function handle(): void
{
if (!current_user_can('manage_options')) {
wp_die('Accès refusé', 403);
}
check_admin_referer(self::NONCE_ACTION);
$enabled = isset($_POST['enabled']) && $_POST['enabled'] === '1';
update_option(self::OPTION_KEY, $enabled ? '1' : '0');
wp_safe_redirect(admin_url('options-general.php?page=bpcab-demo'));
exit;
}
}
Csatlakoztassa src/Plugin/Plugin.php :
<?php
// ... (extrait) ...
use BpcabDemoInfrastructureAdminSettingsAction;
// ... dans boot() ...
$this->container->set(SettingsAction::class, function (): SettingsAction {
return new SettingsAction();
});
$this->container->get(SettingsAction::class)->register();
2) Tesztkapacitás + nonce
teremt tests/integration/SettingsActionTest.php :
<?php
declare(strict_types=1);
namespace BpcabDemoTestsIntegration;
use BpcabDemoInfrastructureAdminSettingsAction;
use WP_UnitTestCase;
final class SettingsActionTest extends WP_UnitTestCase
{
public function setUp(): void
{
parent::setUp();
update_option(SettingsAction::OPTION_KEY, '0');
}
public function tearDown(): void
{
// Nettoyage : évite les tests interdépendants.
delete_option(SettingsAction::OPTION_KEY);
parent::tearDown();
}
public function testActionRefuseSansCapacite(): void
{
$userId = self::factory()->user->create(['role' => 'subscriber']);
wp_set_current_user($userId);
$_POST = [
'_wpnonce' => wp_create_nonce(SettingsAction::NONCE_ACTION),
'enabled' => '1',
];
// wp_die() jette une exception dans la suite de tests WP.
$this->expectException(WPDieException::class);
do_action('admin_post_bpcab_demo_save');
}
public function testActionRefuseSansNonceValide(): void
{
$userId = self::factory()->user->create(['role' => 'administrator']);
wp_set_current_user($userId);
$_POST = [
'_wpnonce' => 'nonce_invalide',
'enabled' => '1',
];
$this->expectException(WPDieException::class);
do_action('admin_post_bpcab_demo_save');
}
public function testActionMetAJourOptionAvecNonceEtCapacite(): void
{
$userId = self::factory()->user->create(['role' => 'administrator']);
wp_set_current_user($userId);
$_POST = [
'_wpnonce' => wp_create_nonce(SettingsAction::NONCE_ACTION),
'enabled' => '1',
];
// On évite la redirection réelle en interceptant wp_redirect.
add_filter('wp_redirect', static function (string $location): string {
// On renvoie une URL neutre, mais on laisse WordPress continuer.
return $location;
});
try {
do_action('admin_post_bpcab_demo_save');
} catch (WPDieException $e) {
// Certains environnements de test peuvent convertir exit en die.
// On tolère, l'essentiel est l'état final.
}
$this->assertSame('1', get_option(SettingsAction::OPTION_KEY));
}
}
Ez a teszt egy olyan pontot illusztrál, amivel gyakran találkozom: Az adminisztrációs kezelők végül kilépnek()A tesztelés során ez úgy fordítható le, hogy wp_die vagy egy kivétel a szekvenciától függően. A minta: az állapotot (opció, poszt metaadatai stb.) ellenőrzöd a pontos kimeneti adatfolyam helyett.
Hasznos hivatalos források:
7. lépés: Gyárak, szerelvények, adatbázis és tisztítás
A „hibás” integrációs tesztek gyakran egy rosszul megtisztított adatbázisállapotból, vagy egy másiktól függő tesztből erednek. A WP tesztcsomag gyárakat biztosít, de fegyelmezettnek kell maradni:
- Hozd létre a bejegyzéseidet/felhasználóidat/kifejezéseidet a tesztben.
- kézi beállítások/tranziensek tisztítása
tearDown(), - Ne használjon fixen kódolt azonosítót.
Példa: bejegyzés létrehozása és szűrő tesztelése
Adjunk hozzá egy szűrőt, amely egy adott beállításnak megfelelően módosítja a bejegyzés címét.
teremt src/Infrastructure/Hooks/TitlePrefixHook.php :
<?php
declare(strict_types=1);
namespace BpcabDemoInfrastructureHooks;
final class TitlePrefixHook
{
public const OPTION_PREFIX = 'bpcab_demo_title_prefix';
public function register(): void
{
add_filter('the_title', [$this, 'filterTitle'], 10, 2);
}
public function filterTitle(string $title, int $postId): string
{
$prefix = (string) get_option(self::OPTION_PREFIX, '');
$prefix = trim($prefix);
if ($prefix === '' || is_admin()) {
return $title;
}
// Évite de préfixer les titres vides.
if (trim($title) === '') {
return $title;
}
return $prefix . ' ' . $title;
}
}
Csatlakoztassa Plugin.php mint más szolgáltatásoknál.
teremt tests/integration/TitlePrefixHookTest.php :
<?php
declare(strict_types=1);
namespace BpcabDemoTestsIntegration;
use BpcabDemoInfrastructureHooksTitlePrefixHook;
use WP_UnitTestCase;
final class TitlePrefixHookTest extends WP_UnitTestCase
{
public function tearDown(): void
{
delete_option(TitlePrefixHook::OPTION_PREFIX);
parent::tearDown();
}
public function testPrefixAppliqueSurTitreFront(): void
{
update_option(TitlePrefixHook::OPTION_PREFIX, '[VIP]');
$postId = self::factory()->post->create([
'post_title' => 'Mon article',
'post_status' => 'publish',
]);
// Simule un contexte front.
$this->go_to(get_permalink($postId));
$this->assertFalse(is_admin());
$title = get_the_title($postId);
$this->assertSame('[VIP] Mon article', $title);
}
public function testNePrefixPasSiOptionVide(): void
{
update_option(TitlePrefixHook::OPTION_PREFIX, '');
$postId = self::factory()->post->create([
'post_title' => 'Mon article',
'post_status' => 'publish',
]);
$this->go_to(get_permalink($postId));
$this->assertSame('Mon article', get_the_title($postId));
}
}
Ez a teszt a következők ellen véd:
- rossz horog (akció és a szűrő összekeverése),
- egy prioritás, amely megváltoztatja az eredményt (ha egy másik bővítmény is előtaggal látja el),
- egy nem kezelt adminisztrációs/front kontextus.
8. lépés: Automatizálás GitHub Actions segítségével (WP/PHP mátrix)
CI nélkül a tesztelés továbbra is „opcionális” marad. CI-vel a regresszió PR-kudarccá válik. Itt kezd kifizetődővé válni.
1) GitHub Actions munkafolyamat hozzáadása
teremt .github/workflows/tests.yml (a repo gyökerében, nem benne wp-content (ha a bővítményed egy dedikált tárház):
name: Tests
on:
push:
pull_request:
jobs:
phpunit:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ["8.1", "8.2", "8.3"]
wp: ["6.9.4"]
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wp_tests
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -h 127.0.0.1 -proot"
--health-interval=10s
--health-timeout=5s
--health-retries=10
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: composer:v2
coverage: none
- name: Cache Composer
uses: actions/cache@v4
with:
path: |
vendor
~/.composer/cache
key: composer-${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('composer.lock') }}
- name: Install dependencies
run: composer install --no-interaction --prefer-dist
- name: Checkout wordpress-develop
run: |
mkdir -p $HOME/wp-tests
cd $HOME/wp-tests
git clone --depth=1 --branch ${{ matrix.wp }} https://github.com/WordPress/wordpress-develop.git
- name: Run unit tests
run: composer test:unit
- name: Run integration tests
env:
WP_DEVELOP_DIR: ${{ env.HOME }}/wp-tests/wordpress-develop
WP_TESTS_DB_NAME: wp_tests
WP_TESTS_DB_USER: root
WP_TESTS_DB_PASS: root
WP_TESTS_DB_HOST: 127.0.0.1
run: composer test:integration
Realisztikus megjegyzések:
- A címke
6.9.4-banwordpress-developlétezik, ha egy ág/címke egyezik. Egyébként használja a--branch 6.9vagy egy commit. Alkalmazkodj az olvasás időpontjában aktuális központi kiadási stratégiához. - Ha éjszaka telepíted a WP-t, számíts átmeneti hibákra. Én gyakran használom "engedélyezett hibák" módban kritikus bővítményekhez.
Hivatkozás: hivatalos törzsbetét wordpress-fejlesztés.
A teljes eredmény
Ha mindent egyszerre szeretnél másolni, itt van a minimális assembly (a már bemutatott fájlok kivételével). Ellenőrizd az elérési utakat.
Fa szerkezet
bpcab-demo/
bpcab-demo.php
composer.json
phpunit.unit.xml
phpunit.integration.xml
src/
Domain/
Greeting.php
Infrastructure/
Admin/
SettingsAction.php
Hooks/
HelloHook.php
TitlePrefixHook.php
Plugin/
Plugin.php
Container/
Container.php
tests/
bootstrap-unit.php
bootstrap-integration.php
unit/
GreetingTest.php
integration/
ShortcodeHelloTest.php
SettingsActionTest.php
TitlePrefixHookTest.php
Gyors testreszabás
- Lakosztály hozzáadása szerződés (kompatibilitási tesztek), ha a bővítményed nyilvános szűrőket tesz elérhetővé.
- hozzáad phpstan fejlesztés alatt áll, ha zárolni szeretnéd a típusokat (ez nagyon hatékony a „Domain/Infrastruktúra” architektúrával).
- Szolgáltatások létrehozásának áthelyezése egy Szolgáltató ha a bővítményed növekszik.
Alkalmazkodni Divi 5 / Elementor / Avada
Az oldalkészítők nem akadályozzák meg a tesztelést. A lényeg: teszteld a logika és a te WordPress integrációk, nem a builder felhasználói felületét (ami inkább az e2e tesztelésről szól).
Divi 5
- Ha közzéteszel egy rövidkódot, mint például
[bpcab_hello]A Divi könnyen használhatja egy „Kód” vagy „Szöveg” modulon keresztül. - Ajánlott integrációs teszt: rövid kód (do_shortcode) (már megtörtént), és ha eszközöket adsz hozzá, teszteld
wp_enqueue_scripts(hook + függőségek).
Elementor
- A modul szokás ElementorSzétválasztom a widget osztályt (infrastruktúra) és a "renderelő" szolgáltatást (tartomány). A renderelő egy egység, a widgetet integrációban tesztelem (a regisztrációs hook meghívásának ellenőrzésével).
- Egy gyakori szélsőséges eset, amit látok, hogy a widget regisztrációs kódja túl korán fut. Teszteld a prioritást a következőn:
elementor/widgets/register(vagy azzal egyenértékű hook az Elementor verziójától függően).
Avada (fúziós építő)
- Ugyanez a logika érvényesül: az Avada rövidkódok/elemek becsomagolhatják a kimenetet. Hasznos teszt: ellenőrizze, hogy a rövidkód stabil, megkerült karakterláncot ad-e vissza.
- Ha „fúziós elemet” adsz meg, izoláld az opciók (tömbök) generálását, és teszteld egység módban.
Végső ellenőrzés
- A bővítményen belül: Extensions → aktiválja a „BPCAB demó (tesztelhető)” funkciót.
- Hozz létre egy oldalt a következővel:
[bpcab_hello name="Test"]: a „Hello Test!” feliratnak kell megjelennie. - A parancssori felületen, a bővítmény mappájából:
composer test:unit: zöld lakosztály, nagyon gyors végrehajtás.composer test:integration: zöld lakosztály, lassabb, DB használatban.
- GitHubon: kattints a → „Tesztek” munkafolyamat a mátrix PHP verzióira vált.
Ha az eredmény nem a vártnak megfelelő
| tünet | Valószínű ok | igazolás | Megoldás |
|---|---|---|---|
| PHPUnit: „Az osztály nem található” | A PSR-4 automatikus betöltése helytelenül van konfigurálva. | néz composer.json és a fájlnévtér |
composer dump-autoload, helyes BpcabDemo\ → src/ |
| Integráció: „A WordPress tesztmappa nem található” | WP_DEVELOP_DIR hibás |
echo $WP_DEVELOP_DIR / ellenőrizze az elérési utat |
Irány a helyes út wordpress-develop |
| Integráció: „Hiba az adatbázis-kapcsolat létrehozásakor” | A tesztadatbázis nem létezik, vagy a hitelesítő adatok helytelenek | Jelentkezzen be a MySQL-be a hitelesítő adatokkal | létrehoz wp_testshelyes host/user/pass |
| A rövidkód nincs mentve teszt módban. | A bővítmény nincs betöltve muplugins_loaded |
ellenőrzés tests/bootstrap-integration.php |
Javítsa ki a require .../bpcab-demo.php (útvonal) |
| PHP hiba: „Hívás egy definiálatlan add_action() függvényre” az egységben | Egy egységteszt betölti a WP-től függő kódot | A veremkövetés megtekintése | Váltsd át a logikát Domaingúnyolódás vagy tesztelés az integrációban |
Problémák, amikkel gyakran találkozom hibaelhárításkor:
- A kód rossz helyre lett másolva (pl.
tests/bootstrap-integration.phpberaknisrc/). - Hiányzó pontosvessző a bootstrap által betöltött fájlban: A PHPUnit még a teszt megjelenítése előtt leáll.
- Művelet/szűrő zavar: Ön használja
add_actionhelyettadd_filter(vagy fordítva), és a teszt „semmit sem lát”. - Éles környezetben tesztelsz "csak hogy lásd": a teszt adatbázis felülírja a beállításokat. Ne tedd ezt.
- A bővítményed túl korán/túl későn töltődött be: a hookok nem érhetők el, vagy a függőségek nincsenek betöltve.
Gyakori buktatók és hibák
| Hiba | Okoz | Megoldás |
|---|---|---|
| Instabil (egyenetlen) integrációs tesztek | A WP állapotának teljes kitisztítása nem történt meg (opciók, tranziensek, hookok hozzáadva) | Tiszta be tearDown()kerülje a globális egysejtűeket, korlátozza a mellékhatásokat |
| „A fejlécek már elküldve” | A teszt átirányítást/kilépést indít el a pufferelés előtt | Végső állapot tesztelése, elfogás wp_redirectKerüld a fejléceken való állítást |
| „A fejlécinformációk nem módosíthatók” csak konfigurációs konfigurációban | Különbségek a PHP kiterjesztésekben / kimeneti pufferelésben | Ne a PHPUnit HTTP-folyamára hagyatkozz; használj végponttól végpontig terjedő teszteket erre. |
| Egy régi oktatóanyag elavult szkripteket ajánl. | A PHPUnit / WP tesztcsomag fejlődése | Összhangban van a jelenlegi alapvető dokumentációval és a wordpress-develop (2026. április) |
| A kódrészletek bővítménye elrontja a teszteket | Futásidejű kód betöltése a tesztkörnyezetbe | Teszteld a bővítményedet minimális környezetben; tiltsd le a felesleges mu-pluginokat |
| Elavult PHP-vel kapcsolatos hiba | CI vagy helyi gép PHP 7.x/8.0-n | Frissítsen PHP 8.1+ verzióra (lásd Támogatott PHP verziók) |
Változat / alternatíva
„WordPress tesztcsomag nélkül” opció (csak egység)
Ha a bővítményed elsősorban tisztán logikai jellegű (számítások, elemzés, API hasznos adat generálása), akkor a következőkre korlátozhatod magad:
- Zeneszerző + PHPUnit,
- egységtesztek
src/Domain, - Az integrációs teszteket egy kis számú manuális „füstteszt” váltotta fel.
Ez elfogadható egy egyszerű belső bővítmény esetében, de elveszíti a WP hookok, szerepkörök, nonce-ok és viselkedések lefedettségét.
„Haladóbb” opció: integrációs tesztelés egy rövid távú környezettel
Komplex bővítmények esetén gyakran szívesebben futtatom az integrációt egy eldobható környezetben:
- Docker Compose (MySQL + WordPress + CLI),
- WordPress telepítés Elefántcsontparton,
- PHPUnit tesztek + esetleg Playwright/Cypress az e2e-hez.
Nehezebb, de csökkenti a meglepetéseket a gyártáshoz közeli halmoknál.
Biztonsági, teljesítménybeli és karbantartási tippek
- Biztonság Mindig teszteld az „elutasított” elérési utakat (érvénytelen képességek, nonce-ok). A biztonsági hibák gyakran abból fakadnak, hogy „adminisztrátorként működik”.
- Szigetelés Soha ne oszd meg a tesztadatbázist semmi mással. Még helyben sem.
- Teljesítmény A tesztek 80%-át egységtesztelésben kell tartani. Az integrációs teszteknek az assembly-t kell validálniuk, nem pedig minden esetet újrajátszani.
- Karbantartás : amikor a WordPress 6.9.x fejlődik, azt szeretnéd, hogy a konfigurációs felület a felhasználók előtt jelezze, hogy „elromlott”.
- Kompat : ha több WP verziót támogatsz, készíts egy CI mátrixot (pl. 6.7, 6.8, 6.9.4) és fogadj el néhány feltételes módosítást.
Megy tovább
- Tesztek hozzáadása REST API (útvonalak, visszahívási jogosultságok, sémák).
- Tesztelje az adatbázis-migrációit (tábla létrehozása,
dbDelta()) az integrációban. - Állítsa be a Szolgáltató (tisztítószertartály) és ellenőrizze a vezetékeket.
- Lépés hozzáadása statikus elemzés (PHPStan/Zsoltár) + kódolási szabványok (PHPCS WordPress) a CI-n.
- Ha JS-ed (blokkok) vannak, add hozzá a Jest/Vitest-et a következőn keresztül: @wordpress/scripts és válassza szét a csővezetékeket.
erőforrás
- WordPress Core kézikönyv – PHPUnit
- GitHub – WordPress/wordpress-fejlesztés
- WP_UnitTestCase (referencia)
- Bővítmény kézikönyv – Nonces
- add_shortcode() (hivatkozás)
- PHPUnit hivatalos dokumentációja
- WordPress Core Trac (hasznos a tesztelés/CI-változások nyomon követéséhez a magoldalon)
- PHP kézikönyv
FAQ
Miért kellene különválasztani az „egységet” és az „integrációt” ahelyett, hogy mindent betöltött WordPress-szel tesztelnénk?
Mivel a WordPress betöltése a teszteket lassúvá, megbízhatatlanná és nehezebben diagnosztizálhatóvá teszi, megtartom a WordPress-t az assembly (hookok, szerepkörök, adatbázis) validálásához, az üzleti logikát pedig tiszta PHP-ben tesztelem.
Szükséges a PHPUnit 11?
Nem, de a PHP 8.1+ verziókon ez egy következetes és karbantartott választás. Ha a stacked korlátozott, ennek megfelelően igazítsd a verziót. composer.jsonLásd a PHPUnit dokumentációjának kompatibilitási részét.
Miért klónozzuk a WordPress-fejlesztést egy „normál” WordPress helyett?
Mivel a WP tesztkészlete itt található wordpress-develop/tests/phpunitMás módon is bütykölhetsz vele, de akkor a mag által már karbantartott szkripteket fogod újra feltalálni.
Nagyon lassúak az integrációs tesztjeim. Mit tegyek?
Csökkentsd a számukat, fókuszálj az integrációs pontokra, a többit pedig helyezd át egységtesztelésekre. CI-n használj Composer gyorsítótárakat, és kerüld a túl sok előzmény klónozását (ezért --depth=1).
Hogyan tesztelhetek egy olyan horgot, ami egy sorrendtől/prioritástól függ?
Teszteld a végső hatást (kimenet/állapot), és adj hozzá egy tesztet, amely ellenőrzi a visszahívás meglétét a következővel: has_action() / has_filter() Ha releváns. Megjegyzés: ezek a függvények a regisztrációt validálják, nem a végrehajtást.
Hogyan teszteljünk olyan kódot, ami működik exit ?
Általában teszteled az állapotot (frissítési opció, bejegyzés létrehozva), és amit tudsz, lehallgatsz (szűrés). wp_redirectNe harcolj a „kilépés érvényesítéséért”.
„Hívás egy definiálatlan esc_html() függvényre” hibaüzenetet látok egy egységtesztben. Ez normális?
Igen : esc_html() egy WordPress függvény. Ha egységtesztet szeretnél, izoláld a logikát egy tiszta PHP osztályban, és teszteld az escape-elést integrációban, vagy injektálj egy escape-elési stratégiát (fejlettebb).
Tesztelhetem az Elementort/Divi-t/Avadát PHPUnit-tal?
Tesztelheted az integrációs kódodat (pl. „a widgetem a megfelelő hookra regisztrál”), de a teljes felhasználói felületet nem. A felhasználói felülethez használj végponttól végpontig tartó teszteket (Playwright/Cypress) egy tesztoldalon.
Elköteleződjek? vendor/ a bővítményemben?
A Composert nem tartalmazó bővítmények esetében sok ilyen található. vendor/Egy Composeren keresztül kezelt belső bővítmény esetében nem. Minden esetben a függőségeket a CI-re telepíted.
Hogyan kezelhetem a többverziós kompatibilitást a WordPressben?
Adj hozzá egy CI-mátrixot több WP-verzióhoz, és tartsd függetlennek az egységteszteket. Az alapvető változásokhoz kövesd a ticketeket a következő címen: lámpaláz és a PR-ek GitHub.
Mi a teendő, ha egy régi oktatóanyag-részlet már nem működik a WordPress 6.9.4-en?
Ne erőltesd. Igazodj a jelenlegi WP tesztcsomaghoz (wordpress-develop), és ennek megfelelően alakítsd át a Bootstrap-edet. Az elavult blogokon található régi teszttelepítő szkriptek gyakran meghibásodnak a PHPUnit (megváltozott API) és a csomag elérési útjai miatt.