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


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.php
  • bpcab-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 ExtensionsTelepí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/phpunit utó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_tests létezik,
  • Az adatbázis-felhasználó rendelkezik a jogokkal,
  • nem tetted localhost miközben a MySQL figyeli 127.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 -ban wordpress-develop létezik, ha egy ág/címke egyezik. Egyébként használja a --branch 6.9 vagy 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

  1. A bővítményen belül: Extensions → aktiválja a „BPCAB demó (tesztelhető)” funkciót.
  2. Hozz létre egy oldalt a következővel: [bpcab_hello name="Test"] : a „Hello Test!” feliratnak kell megjelennie.
  3. 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.
  4. 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.php berakni src/).
  • 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_action helyett add_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


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.