Pruebas unitarias para WordPress: Guía del desarrollador para 2026

Pruebas unitarias para WordPress: Guía del desarrollador para 2026

Última verificación: 12 de octubre de 2026
18 min de lectura
Tutorial
Desarrollador full-stack

La automatización de pruebas en el desarrollo con WordPress ha pasado de ser un añadido opcional a convertirse en un requisito indispensable para cualquier entorno de producción profesional. Durante años, numerosos equipos confiaron exclusivamente en la verificación manual: recargar el navegador, hacer clic en formularios del panel de administración y comprobar datos en la base tras aplicar cambios en el código. Esta metodología resulta insostenible cuando el proyecto crece e interactúan múltiples tipos de contenido personalizados, endpoints de la REST API, taxonomías avanzadas y lógica de negocio compleja. Una pequeña regresión en un filtro poco frecuentado puede pasar inadvertida hasta que los pedidos de los clientes fallan en el entorno real.

Una estrategia de pruebas profesional organiza el control de calidad en capas complementarias. En la base se encuentran las pruebas unitarias, que se ejecutan en milisegundos sin cargar WordPress ni requerir conexión con la base de datos. Por encima se sitúan las pruebas de integración, que comprueban la interacción con el esquema MySQL y las funciones del núcleo. En la capa superior operan las pruebas funcionales y de aceptación en navegador. Diseñar una infraestructura de pruebas fiable en 2026 requiere una separación estricta de estas capas y el uso experto de herramientas como PHPUnit 10 y 11, Brain Monkey, Mockery, wp-browser y wp-env.

#Principios de las pruebas unitarias y aislamiento total

Una prueba unitaria genuina evalúa una única función o método de clase en completo aislamiento de dependencias externas. En WordPress, este aislamiento supone un reto arquitectónico, ya que las convenciones clásicas dependen de funciones globales como get_post(), get_option() y apply_filters(). Si se invocan estas funciones dentro de la lógica de dominio sin cargar el núcleo de WordPress, la ejecución en un entorno PHP estándar genera de inmediato errores fatales por funciones no definidas.

Pretender ejecutar pruebas unitarias levantando todo el entorno de WordPress y su base de datos para cada caso de prueba destruye el ciclo de retroalimentación del equipo. Si la suite tarda diez minutos en completarse, los programadores dejan de ejecutarla antes de confirmar sus cambios. Las pruebas unitarias deben completarse en pocos segundos. Para alcanzar esa velocidad, la lógica de negocio debe aislarse de la base de datos y de las variables globales mediante dobles de prueba y simulación de funciones.

El código verificable en WordPress nace del diseño arquitectónico. Las clases deben desacoplar la lógica de dominio de las funciones del CMS. En lugar de ejecutar update_post_meta() en mitad de un cálculo de tarifas, los valores deben transferirse a métodos puros que devuelvan el resultado calculado. Las interacciones con las funciones nativas de WordPress deben encapsularse en adaptadores o servicios, permitiendo a los entornos de prueba simular su comportamiento de forma controlada.

#Simulación de hooks y filtros con Brain Monkey

Brain Monkey es la herramienta de referencia para realizar pruebas unitarias en WordPress con aislamiento absoluto. Desarrollada específicamente para simular funciones, acciones y filtros sin inicializar los archivos del núcleo, Brain Monkey permite ejecutar cientos de aserciones en fracciones de segundo.

Brain Monkey intercepta las llamadas a add_action(), add_filter(), do_action() y apply_filters(). Esto permite verificar con exactitud si una acción se ha vinculado con la prioridad y el número de argumentos previstos, o si un filtro personalizado ha modificado la estructura de datos según lo estipulado.

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Unit;

use Brain\Monkey;
use Brain\Monkey\Actions;
use Brain\Monkey\Filters;
use Brain\Monkey\Functions;
use PHPUnit\Framework\TestCase;
use WPPoland\Billing\InvoiceManager;

final class InvoiceManagerTest extends TestCase {
    protected function setUp(): void {
        parent::setUp();
        Monkey\setUp();
    }

    protected function tearDown(): void {
        Monkey\tearDown();
        parent::tearDown();
    }

    public function test_invoice_creation_triggers_expected_action(): void {
        Actions\expectDone('wppoland_invoice_generated')
            ->once()
            ->with(1042, 599.00);

        Functions\expect('get_option')
            ->with('currency_code', 'EUR')
            ->andReturn('EUR');

        $manager = new InvoiceManager();
        $invoiceId = $manager->createInvoice(1042, 599.00);

        $this->assertSame(1042, $invoiceId);
    }

    public function test_filter_modifies_invoice_total(): void {
        Filters\expectApplied('wppoland_invoice_discount')
            ->once()
            ->with(500.00, 1042)
            ->andReturn(450.00);

        $manager = new InvoiceManager();
        $finalAmount = $manager->applyDiscounts(500.00, 1042);

        $this->assertSame(450.00, $finalAmount);
    }
}

En este caso no interviene ninguna base de datos ni archivo del núcleo. Brain Monkey gestiona el ciclo de vida de los hooks en memoria. La ejecución de Monkey\setUp() en setUp() y de Monkey\tearDown() en tearDown() restablece el estado de los mocks entre casos de prueba, impidiendo interferencias entre métodos.

#Mockery para dependencias complejas y orientación a objetos

Brain Monkey se integra de forma directa con Mockery para simular objetos e interfaces junto a las funciones procedimentales. En plugins empresariales, las clases interactúan con repositorios, clientes HTTP y pasarelas de pago externas. Mockery permite construir dobles de prueba que reproducen interfaces complejas y comprueban la invocación de métodos.

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Unit;

use Mockery;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use PHPUnit\Framework\TestCase;
use WPPoland\Gateways\PaymentClientInterface;
use WPPoland\Orders\OrderProcessor;

final class OrderProcessorTest extends TestCase {
    use MockeryPHPUnitIntegration;

    public function test_order_processes_payment_successfully(): void {
        $paymentClient = Mockery::mock(PaymentClientInterface::class);
        $paymentClient->shouldReceive('charge')
            ->once()
            ->with(120.50, 'EUR')
            ->andReturn((object) ['status' => 'success', 'transaction_id' => 'tx_9981']);

        $processor = new OrderProcessor($paymentClient);
        $result = $processor->process(101, 120.50, 'EUR');

        $this->assertTrue($result->isSuccessful());
        $this->assertSame('tx_9981', $result->getTransactionId());
    }
}

Al utilizar el trait MockeryPHPUnitIntegration, las aserciones de Mockery se contabilizan dentro del registro global de PHPUnit, provocando el fallo inmediato del test si alguna expectativa no llega a cumplirse.

#Patrones avanzados con Mockery en arquitecturas empresariales

En arquitecturas corporativas es habitual recurrir a patrones como contenedores de servicios y repositorios de datos. Al probar un componente que sincroniza inventario con un servicio externo, el conjunto de pruebas no puede emitir peticiones de red reales. Mockery proporciona una sintaxis clara para modelar reintentos y controlar excepciones.

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Unit;

use Mockery;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use PHPUnit\Framework\TestCase;
use WPPoland\Http\ApiClientInterface;
use WPPoland\Sync\InventorySynchronizer;
use RuntimeException;

final class InventorySynchronizerTest extends TestCase {
    use MockeryPHPUnitIntegration;

    public function test_sync_retries_on_network_timeout(): void {
        $apiClient = Mockery::mock(ApiClientInterface::class);

        $apiClient->shouldReceive('fetchProductStock')
            ->twice()
            ->with('SKU-9901')
            ->andReturnValues([
                new RuntimeException('Connection timed out'),
                ['sku' => 'SKU-9901', 'stock' => 45],
            ]);

        $synchronizer = new InventorySynchronizer($apiClient);
        $stock = $synchronizer->syncProduct('SKU-9901');

        $this->assertSame(45, $stock);
    }

    public function test_sync_throws_exception_after_exhausting_retries(): void {
        $apiClient = Mockery::mock(ApiClientInterface::class);
        $apiClient->shouldReceive('fetchProductStock')
            ->times(3)
            ->with('SKU-9901')
            ->andThrow(new RuntimeException('Fatal gateway outage'));

        $this->expectException(RuntimeException::class);
        $this->expectExceptionMessage('Fatal gateway outage');

        $synchronizer = new InventorySynchronizer($apiClient, 3);
        $synchronizer->syncProduct('SKU-9901');
    }
}

Esta técnica valida la recuperación ante incidencias de conectividad y límites de tasa sin depender de servidores remotos.

#Pruebas de integración mediante WP_UnitTestCase

Mientras que las pruebas unitarias validan la lógica aislada, el software en WordPress termina ejecutándose dentro del CMS. Las pruebas de integración comprueban cómo interactúan las consultas WP_Query, los tipos de contenido personalizados, los permisos de usuario y las opciones con el motor de base de datos.

La suite oficial de pruebas de WordPress proporciona la clase WP_UnitTestCase, que extiende la clase base de PHPUnit. Esta clase inicializa WordPress por completo y se conecta a una base de datos de pruebas específica. Además, incorpora fábricas de entidades (factories) que agilizan la creación de publicaciones, términos y usuarios.

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Integration;

use WP_UnitTestCase;
use WP_Query;

final class CustomQueryTest extends WP_UnitTestCase {
    public function test_query_returns_published_enterprise_projects(): void {
        $postId = $this->factory->post->create([
            'post_type'   => 'portfolio',
            'post_status' => 'publish',
            'post_title'  => 'Enterprise Migration',
        ]);

        $draftId = $this->factory->post->create([
            'post_type'   => 'portfolio',
            'post_status' => 'draft',
            'post_title'  => 'Draft Migration',
        ]);

        $query = new WP_Query([
            'post_type'      => 'portfolio',
            'post_status'    => 'publish',
            'posts_per_page' => 10,
        ]);

        $postIds = wp_list_pluck($query->posts, 'ID');

        $this->assertContains($postId, $postIds);
        $this->assertNotContains($draftId, $postIds);
    }
}

Mediante $this->factory se simplifica notablemente la generación de datos de prueba, manteniendo la coherencia de las relaciones relacionales en cada caso.

#Reversión de transacciones de base de datos en pruebas

Las pruebas de integración con operaciones intensivas de escritura pueden ralentizarse en exceso si las tablas deben vaciarse y regenerarse antes de cada método. En las primeras configuraciones de pruebas para WordPress, la constante ejecución de instrucciones DROP TABLE provocaba ejecuciones de muchos minutos.

La clase WP_UnitTestCase resuelve esta dificultad gestionando transacciones de MySQL. Antes de ejecutar cada método, el entorno inicia una transacción. El caso de prueba ejecuta sus consultas, inserta registros y modifica opciones. Durante la fase de desmontaje (tearDown), el ejecutor aplica un ROLLBACK en lugar de suprimir registros de forma individual.

Este mecanismo de reversión ofrece ventajas determinantes:

  • Cada prueba arranca con un estado limpio y predecible de la base de datos.
  • La velocidad de ejecución se mantiene alta porque los datos se descartan en memoria.
  • Los valores de incremento automático de las claves primarias avanzan continuamente, simulando el entorno de producción.

En servidores modernos con MySQL 8.0 o MariaDB 10.11 y tablas InnoDB, las transacciones garantizan un entorno ágil y consistente.

#Entornos locales estandarizados con wp-env

Tradicionalmente, configurar un entorno local exigía complejas secuencias de comandos de consola, servidores locales de base de datos y descargas por Subversion de las ramas de desarrollo. La herramienta oficial @wordpress/env (wp-env) estandariza este procedimiento mediante contenedores Docker.

El archivo de configuración .wp-env.json en la raíz del proyecto define el entorno:

{
  "core": "WordPress/WordPress#master",
  "plugins": [ "." ],
  "config": {
    "WP_DEBUG": true,
    "SCRIPT_DEBUG": true
  },
  "env": {
    "tests": {
      "config": {
        "WP_DEBUG": true
      }
    }
  }
}

Al ejecutar wp-env start se ponen en marcha los contenedores del servidor web y la base MySQL. Para ejecutar las pruebas de integración dentro del contenedor específico, basta con lanzar:

npx wp-env run tests-cli vendor/bin/phpunit

wp-env aísla por completo la base de datos de pruebas de la base de desarrollo local, evitando modificaciones accidentales.

#Pruebas de endpoints de la REST API y validación de esquema

Los endpoints personalizados de la REST API son la piedra angular de arquitecturas desacopladas, aplicaciones móviles y bloques dinámicos. Las pruebas de integración para controladores WP_REST_Controller aseguran el registro de rutas, los controles de permisos, la validación del esquema de datos y los códigos de respuesta HTTP.

WP_UnitTestCase se comunica directamente con la instancia interna de WP_REST_Server. En lugar de enviar tráfico HTTP sobre la red, las peticiones se procesan en memoria con una velocidad óptima.

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Integration;

use WP_UnitTestCase;
use WP_REST_Request;
use WP_REST_Server;

final class OrdersEndpointTest extends WP_UnitTestCase {
    private WP_REST_Server $server;

    protected function setUp(): void {
        parent::setUp();
        global $wp_rest_server;
        $this->server = $wp_rest_server = new WP_REST_Server();
        do_action('rest_api_init');
    }

    public function test_unauthenticated_request_is_rejected(): void {
        $request = new WP_REST_Request('POST', '/wppoland/v1/orders');
        $request->set_header('content-type', 'application/json');
        $request->set_body(wp_json_encode(['item_id' => 42]));

        $response = $this->server->dispatch($request);

        $this->assertSame(401, $response->get_status());
        $data = $response->get_data();
        $this->assertSame('rest_cannot_create', $data['code']);
    }

    public function test_authorized_user_creates_order_successfully(): void {
        $adminId = $this->factory->user->create(['role' => 'administrator']);
        wp_set_current_user($adminId);

        $request = new WP_REST_Request('POST', '/wppoland/v1/orders');
        $request->set_header('content-type', 'application/json');
        $request->set_body(wp_json_encode([
            'item_id'  => 42,
            'quantity' => 2,
            'amount'   => 199.50,
        ]));

        $response = $this->server->dispatch($request);

        $this->assertSame(201, $response->get_status());
        $data = $response->get_data();
        $this->assertArrayHasKey('order_id', $data);
        $this->assertSame(199.50, $data['amount']);
    }
}

La verificación de controladores REST confirma que las cargas JSON incorrectas se desestiman antes de persistir información en las tablas.

#Verificación de migraciones y esquemas de tablas personalizadas

Muchos plugins corporativos incorporan tablas propias para registrar eventos de auditoría o colas de tareas asíncronas. Garantizar que la creación de tablas, la alteración de columnas y la adición de índices ocurran sin pérdida de datos exige pruebas de migración bien planificadas.

En estos casos se evalúa el comportamiento de dbDelta() y la correcta ejecución de sentencias SQL atómicas.

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Integration;

use WP_UnitTestCase;
use WPPoland\Database\MigrationManager;

final class MigrationManagerTest extends WP_UnitTestCase {
    public function test_migration_creates_custom_audit_table(): void {
        global $wpdb;
        $tableName = $wpdb->prefix . 'wppoland_audit_log';

        $wpdb->query("DROP TABLE IF EXISTS {$tableName}");

        $manager = new MigrationManager();
        $manager->runMigrations();

        $tableExists = $wpdb->get_var(
            $wpdb->prepare("SHOW TABLES LIKE %s", $tableName)
        );

        $this->assertSame($tableName, $tableExists);

        $indices = $wpdb->get_results("SHOW INDEX FROM {$tableName}", ARRAY_A);
        $indexNames = wp_list_pluck($indices, 'Key_name');

        $this->assertContains('idx_created_at', $indexNames);
    }
}

Las pruebas de esquema evitan incidencias graves durante las actualizaciones de versiones en servidores de producción.

#Pruebas de aceptación y automatización de navegador con wp-browser

Las pruebas unitarias y de integración se ejecutan desde la consola de comandos, pero determinadas funcionalidades requieren interacción visual en un navegador. Verificar que las opciones del panel de administración se guarden tras hacer clic o que un formulario valide datos en el cliente exige pruebas de aceptación.

wp-browser integra el framework Codeception con las particularidades de WordPress. Proporciona módulos específicos:

  • WPDb: Permite inspeccionar y poblar la base de datos directamente sin necesidad del cargador de PHPUnit.
  • WPLoader: Inicializa WordPress dentro de pruebas funcionales.
  • WPWebDriver: Controla instancias de Chrome o Firefox mediante Selenium o Chromedriver para emular el comportamiento del usuario.
<?php
// Prueba de aceptación funcional con wp-browser
$I = new AcceptanceTester($scenario);
$I->wantTo('verify admin settings save correctly');
$I->loginAsAdmin();
$I->amOnAdminPage('admin.php?page=wppoland-settings');
$I->fillField('#api_key', 'live_secret_key_12345');
$I->click('Save Changes');
$I->see('Settings saved successfully', '.notice-success');
$I->seeInDatabase('wp_options', [
    'option_name'  => 'wppoland_api_key',
    'option_value' => 'live_secret_key_12345',
]);

Estas pruebas evalúan la pila tecnológica al completo, otorgando máxima seguridad antes de cada despliegue.

#Pruebas en bloques de Gutenberg con Jest y Playwright

El desarrollo moderno en WordPress combina lógica backend en PHP con componentes frontend en React. Por este motivo, la verificación de bloques personalizados exige herramientas del ecosistema JavaScript.

El paquete @wordpress/scripts estandariza el entorno de pruebas. Las utilidades puras y las transformaciones de atributos se analizan con Jest, mientras que las interacciones del usuario en el editor se automatizan mediante Playwright.

#Pruebas de atributos y transformaciones con Jest

Jest ejecuta pruebas sobre componentes React y funciones de utilidad sin estado. La sanitización de atributos y el control de versiones obsoletas de bloques son responsabilidades directas de Jest.

import { cleanInvoiceAttributes } from '../src/utils';

describe('Invoice block attribute sanitization', () => {
    it('sets default tax rate when invalid rate is provided', () => {
        const input = { taxRate: -5, clientName: 'WPPoland' };
        const result = cleanInvoiceAttributes(input);
        expect(result.taxRate).toBe(23);
        expect(result.clientName).toBe('WPPoland');
    });

    it('preserves valid vat rates', () => {
        const input = { taxRate: 8, clientName: 'WPPoland' };
        const result = cleanInvoiceAttributes(input);
        expect(result.taxRate).toBe(8);
    });
});

#Pruebas integrales del editor con Playwright

Playwright administra un navegador sin interfaz gráfica, carga el editor Gutenberg, inserta bloques personalizados y comprueba el árbol DOM y los controles de la barra lateral.

import { test, expect } from '@wordpress/e2e-test-utils-playwright';

test.describe('Invoice summary block', () => {
    test.beforeEach(async ({ admin }) => {
        await admin.createNewPost();
    });

    test('inserts block and updates total in sidebar', async ({ editor, page }) => {
        await editor.insertBlock({ name: 'wppoland/invoice-summary' });
        const block = page.locator('[data-type="wppoland/invoice-summary"]');
        await expect(block).toBeVisible();

        await page.fill('input[aria-label="Invoice total"]', '1250');
        await expect(block.locator('.invoice-formatted-amount')).toHaveText('1,250.00 EUR');
    });
});

Playwright previene roturas visuales y desajustes de interfaz que escapan al alcance de las pruebas backend.

#Análisis estático con PHPStan junto a PHPUnit

El análisis estático refuerza las pruebas dinámicas. Mientras las pruebas verifican respuestas concretas ante entradas determinadas, PHPStan examina el código en su totalidad para detectar inconsistencias de tipos, código muerto y llamadas no válidas antes de ejecutar las pruebas.

Con szepeviktor/phpstan-wordpress se dispone de definiciones de tipos completas para el núcleo de WordPress, evitando referencias rotas tanto en la lógica del plugin como en los propios archivos de test.

Configuración en phpstan.neon.dist:

includes:
    - vendor/szepeviktor/phpstan-wordpress/extension.neon

parameters:
    level: 8
    paths:
        - src
        - tests
    excludePaths:
        - tests/Fixtures/*
    bootstrapFiles:
        - tests/bootstrap-unit.php
    checkMissingIterableValueType: false

Ejecutar vendor/bin/phpstan analyse en la integración continua suprime clases enteras de incidencias de tipado.

#Cobertura de código y umbrales de calidad

La medición de cobertura permite identificar rutas de ejecución no exploradas. No obstante, obsesionarse con un cien por ciento resulta contraproducente si incentiva probar métodos triviales en detrimento de reglas de negocio críticas.

En equipos de alto nivel se define un umbral práctico entre el 80% y el 85% para la lógica de dominio, supervisado mediante PCOV o Xdebug 3 en GitHub Actions.

php -d pcov.enabled=1 vendor/bin/phpunit --testsuite=unit --coverage-text --coverage-html=coverage-report

Configurar adecuadamente los bloques de exclusión en PHPUnit asegura que los cálculos se centren en el código productivo y no en librerías de terceros.

#Integración continua en GitHub Actions sobre PHP 8.2 y 8.3

Las pruebas automatizadas ofrecen su verdadero rendimiento cuando se ejecutan en cada confirmación y pull request. El flujo de trabajo garantiza que ningún cambio se integre sin superar las pruebas en todas las versiones de PHP contempladas.

Un flujo representativo en GitHub Actions comprueba PHP 8.2 y PHP 8.3 utilizando el servicio MySQL 8.0:

name: Test Suite

on:
  push:
    branches: [ master, main ]
  pull_request:
    branches: [ master, main ]

jobs:
  unit-tests:
    name: PHPUnit on PHP ${{ matrix.php }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        php: ['8.2', '8.3']

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          coverage: none
          tools: composer:v2

      - name: Install Composer dependencies
        run: composer install --prefer-dist --no-progress

      - name: Run unit test suite
        run: vendor/bin/phpunit --testsuite=unit

  integration-tests:
    name: Integration Tests on PHP ${{ matrix.php }}
    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: ['8.2', '8.3']

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          extensions: mysqli, pdo_mysql
          coverage: none
          tools: composer:v2

      - name: Install dependencies
        run: composer install --prefer-dist --no-progress

      - name: Run integration tests
        env:
          WP_DB_HOST: 127.0.0.1
          WP_DB_NAME: wordpress_test
          WP_DB_USER: root
          WP_DB_PASS: root
        run: vendor/bin/phpunit --testsuite=integration

La separación de tareas permite obtener resultados de las pruebas unitarias en cuestión de segundos tras cada envío.

#Arquitectura de carpetas y organización del proyecto

Una estructura limpia clarifica la naturaleza de cada prueba y su necesidad de base de datos.

my-enterprise-plugin/
├── .github/
│   └── workflows/
│       └── tests.yml
├── .wp-env.json
├── composer.json
├── phpunit.xml.dist
├── src/
│   ├── Billing/
│   ├── Gateways/
│   └── Plugin.php
└── tests/
    ├── bootstrap-unit.php
    ├── bootstrap-integration.php
    ├── Unit/
    │   ├── Billing/
    │   └── Gateways/
    ├── Integration/
    │   ├── DatabaseQueryTest.php
    │   └── HookRegistrationTest.php
    └── Fixtures/
        └── sample-invoice.json

#Configuración de phpunit.xml.dist para múltiples suites

El archivo XML coordina las distintas suites de pruebas:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
    bootstrap="tests/bootstrap-unit.php"
    colors="true"
    cacheDirectory=".phpunit.cache"
    executionOrder="depends,defects"
    requireCoverageMetadata="false"
    beStrictAboutOutputDuringTests="true"
    failOnRisky="true"
    failOnWarning="true">
    <testsuites>
        <testsuite name="unit">
            <directory suffix="Test.php">tests/Unit</directory>
        </testsuite>
        <testsuite name="integration">
            <directory suffix="Test.php">tests/Integration</directory>
        </testsuite>
    </testsuites>
    <source>
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </source>
</phpunit>

Esto permite al desarrollador ejecutar pruebas unitarias ágiles mientras programa y la totalidad de la suite antes de enviar una solicitud de cambio.

#Matriz de pruebas y lista de comprobación de calidad

La adopción de pruebas automáticas exige constancia y revisiones periódicas de la arquitectura técnica.

Nivel de pruebaHerramientasVelocidadDependencia de base de datosPropósito primordial
Pruebas unitariasPHPUnit 10/11, Brain Monkey, MockeryMilisegundosNinguna (En memoria)Lógica pura de dominio, cálculos y filtros
Pruebas de integraciónWP_UnitTestCase, wp-envSegundosBase de pruebas MySQLConsultas WP_Query, persistencia y prioridad de hooks
Pruebas de aceptaciónwp-browser, CodeceptionSegundos a minutosNavegador headless + DBFormularios de administración, permisos y pasarelas
Pruebas de bloques e2ePlaywright, @wordpress/scriptsMinutosEntorno DockerEditor Gutenberg, controles laterales y HTML generado

Recomendaciones para el mantenimiento:

  1. Aislamiento riguroso: Evitar llamadas a la base de datos dentro de pruebas unitarias.
  2. Reversión transaccional: Mantener la rapidez de las pruebas de integración revirtiendo escrituras.
  3. Verificación continua: Ejecutar pruebas en PHP 8.2 y 8.3 en cada confirmación de código.
  4. Control de bloques: Validar la persistencia de atributos y transformaciones de Gutenberg.
  5. Refactorización continua: Desacoplar la lógica de dominio de las plantillas de presentación.

Conoce más sobre nuestros métodos de ingeniería y servicios de desarrollo WordPress profesional en WPPoland.

#Estrategias para proyectos multilingües y extensiones de terceros

En desarrollos internacionales, los plugins suelen interactuar con extensiones multilingües como Polylang o WPML, además de plataformas de comercio como WooCommerce. La ausencia de pruebas sobre los filtros de internacionalización puede provocar que textos en el carrito o notificaciones por correo aparezcan en el idioma incorrecto.

Al elaborar pruebas unitarias para módulos de traducción conviene simular las funciones de localización mediante Brain Monkey, garantizando que las cadenas de sustitución conserven el contexto adecuado:

<?php
declare(strict_types=1);

namespace WPPoland\Tests\Unit;

use Brain\Monkey\Functions;
use PHPUnit\Framework\TestCase;
use WPPoland\I18n\Translator;

final class TranslatorTest extends TestCase {
    public function test_translates_message_with_placeholder(): void {
        Functions\expect('__')
            ->once()
            ->with('Order #%d completed', 'wppoland')
            ->andReturn('Pedido #%d completado');

        $translator = new Translator();
        $message = $translator->formatOrderMessage(105);

        $this->assertSame('Pedido #105 completado', $message);
    }
}

En las pruebas de integración se supervisa el filtro locale para asegurar que el cambio dinámico de idioma durante una sesión de usuario no contamine la caché de traducciones.

#Diagnóstico y optimización de pruebas lentas

A medida que el proyecto incorpora más casos de prueba, el tiempo total de ejecución se convierte en un aspecto clave para la productividad. PHPUnit ofrece funciones integradas de diagnóstico para identificar los métodos más costosos.

El parámetro --profile ayuda a localizar pruebas que consumen recursos de forma excesiva:

vendor/bin/phpunit --testsuite=integration --profile

Cuando un caso de integración supera los 200 milisegundos, el motivo suele encontrarse en la ausencia de índices en tablas temporales de MySQL, cadenas recursivas de hooks en el núcleo o lecturas repetidas de archivos XML sin caché.

Siguiente paso

Transforma el artículo en una implementación real

Este bloque refuerza el enlazado interno y lleva al lector al siguiente paso más útil dentro de la arquitectura del sitio.

¿Quieres implementar esto en tu sitio?

Si quieres transformar el artículo en mejoras concretas, rediseño o un plan de implementación, puedo cerrar el alcance y ejecutar.

Cluster relacionado

Explora otros servicios WordPress y base de conocimiento

Refuerza tu negocio con soporte técnico profesional en áreas clave del ecosistema WordPress.

FAQ del artículo

Preguntas frecuentes

Respuestas prácticas para aplicar el tema en la ejecución real.

SEO-readyGEO-readyAEO-ready4 Q&A
¿Por qué debería hacer pruebas si puedo simplemente actualizar la página?#
Las pruebas manuales son lentas y propensas a errores. Las pruebas unitarias se ejecutan en milisegundos y verifican miles de rutas lógicas al instante, asegurando que un pequeño cambio no rompa una funcionalidad crítica en otro lugar.
¿Necesito una base de datos para las pruebas unitarias?#
Las pruebas unitarias puras deben ser 'agnósticas a la base de datos' usando mocks. Las pruebas de integración, sin embargo, usan una base de datos de prueba temporal (a menudo en Docker) para verificar resultados reales de WP_Query.
¿Vale la pena el tiempo extra de las pruebas?#
Sí. A largo plazo, ahorra cientos de horas de depuración y previene costosos 'hotfixes' en servidores de producción.
¿Se pueden probar los bloques de Gutenberg?#
Absolutamente. En 2026, usamos Jest junto con el paquete oficial de scripts de WordPress para probar el renderizado y atributos de bloques.

¿Necesitas un FAQ adaptado a tu sector y mercado? Preparamos una versión alineada con tus objetivos de negocio.

Hablemos

Artículos Relacionados