A automação de testes no desenvolvimento com WordPress evoluiu de um complemento opcional para um requisito elementar em sistemas empresariais em produção. Durante muitos anos, equipas de engenharia apoiaram a garantia de qualidade em verificações manuais: atualizar janelas de navegação, submeter formulários no painel wp-admin e verificar tabelas na base de dados após pequenas alterações de código. Essa abordagem torna-se insustentável à medida que a plataforma cresce e integra tipos de conteúdo personalizados, pontos finais da REST API, taxonomias complexas e regras de negócio exigentes. Uma pequena regressão num filtro raramente utilizado pode permanecer oculta até que o processamento de encomendas falhe no ambiente de produção.
Uma estratégia moderna de testes divide o controlo de qualidade em camadas bem delineadas. Na base encontram-se os testes unitários, executados em milissegundos sem arranque do WordPress e sem ligação a bases de dados. Imediatamente acima situam-se os testes de integração, responsáveis por validar a interação com o esquema MySQL e as funções de base do WordPress. No topo atuam os testes de aceitação e de navegador. Criar um conjunto sustentável de testes em 2026 exige rigor na separação destas camadas e a utilização de ferramentas consolidadas como o PHPUnit 10 e 11, Brain Monkey, Mockery, wp-browser e wp-env.
Fundamentos dos testes unitários e princípio de isolamento
Um teste unitário autêntico analisa uma única função ou método de classe em total isolamento face a dependências externas. No WordPress, esse isolamento representa um desafio de arquitetura considerável, uma vez que a base de código convencional depende de funções globais como get_post(), get_option() e apply_filters(). Quando tais funções são invocadas no interior da lógica de domínio sem o núcleo do WordPress carregado, a execução num ambiente PHP padrão resulta de imediato em erros fatais devido a funções não definidas.
Tentar executar testes unitários inicializando todo o ecossistema do WordPress e a base de dados para cada método destrói o ciclo de feedback dos programadores. Quando uma suite demora dez minutos a correr, a equipa deixa de executá-la antes de enviar código para o repositório. Os testes unitários puros têm de terminar em escassos segundos. Para atingir essa rapidez, a lógica de negócio deve ser desacoplada da base de dados e das variáveis globais através de duplos de teste e simulação de funções.
O código testável em WordPress começa no desenho da arquitetura de software. As classes devem isolar a lógica de domínio das interfaces do CMS. Em vez de chamar update_post_meta() no meio de um algoritmo de cálculo de preços, passe os valores como argumentos para métodos puros e devolva o resultado calculado. Quando a interação com as funções nativas for indispensável, encapsule essas chamadas em adaptadores ou serviços, permitindo que as ferramentas de teste simulem o seu comportamento de forma controlada.
Brain Monkey para asserções de ações e filtros
O Brain Monkey é a ferramenta de eleição para realizar testes unitários em WordPress em isolamento completo. Concebido especificamente para simular funções, ações e filtros sem carregar os ficheiros da plataforma, o Brain Monkey possibilita execuções de testes em milissegundos.
O Brain Monkey interceta chamadas a add_action(), add_filter(), do_action() e apply_filters(). Desta forma, os testes podem verificar com rigor se uma ação foi registada com a prioridade e os argumentos corretos, ou se um filtro personalizado manipulou uma estrutura de dados de acordo com o esperado.
<?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);
}
}Neste caso de teste não existem ficheiros do WordPress nem instâncias de base de dados. O Brain Monkey gere o ciclo de vida dos hooks em memória. Chamar Monkey\setUp() em setUp() e Monkey\tearDown() em tearDown() reinicializa o estado dos mocks entre cada teste, evitando contaminações entre métodos.
Mockery para dependências complexas orientadas a objetos
O Brain Monkey colabora diretamente com a biblioteca Mockery para facultar a simulação de objetos e contratos em paralelo com funções procedimentais. Em plugins empresariais de grande escala, as classes comunicam com repositórios, clientes HTTP e gateways de pagamento externas. O Mockery permite construir duplos de teste que reproduzem interfaces complexas e validam chamadas 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());
}
}Ao adotar o trait MockeryPHPUnitIntegration, as asserções do Mockery passam a constar da contagem global do PHPUnit, fazendo falhar o teste de imediato caso uma expectativa não seja cumprida.
Padrões avançados com Mockery na arquitetura de plugins
Em ambientes empresariais encontramos frequentemente contentores de injeção de dependências e camadas de abstração de dados. Ao testar uma rotina que sincroniza artigos com um serviço externo de gestão de armazém, o conjunto de testes não pode realizar pedidos de rede verdadeiros. O Mockery oferece sintaxe limpa para modelar tentativas de repetição e cenários de exceção.
<?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');
}
}Este modelo assegura que contingências de rede e limites de tráfego são verificados sem dependência de servidores externos.
Testes de integração com a classe WP_UnitTestCase
Embora os testes unitários verifiquem a lógica isolada, o software desenvolvido para WordPress é executado no contexto do CMS. Os testes de integração avaliam como as consultas WP_Query, os tipos de conteúdo personalizados, as permissões de utilizador e as opções interagem com o motor relacional.
A suite oficial do WordPress disponibiliza a classe WP_UnitTestCase, que estende a classe base do PHPUnit. Esta classe inicializa integralmente o WordPress e liga-se a uma base de dados de teste isolada. Fornece também fábricas de dados (factories) que automatizam a criação de artigos, categorias e utilizadores.
<?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);
}
}Graças a $this->factory, a criação de dados de teste reduz-se a breves instruções, garantindo registos completos e coerentes na base de dados.
Reversão de transações na base de dados em testes
Testes de integração que executam gravações regulares podem abrandar significativamente se as tabelas tiverem de ser limpas e migradas antes de cada método. Nos primeiros ambientes de teste de WordPress, o recurso a comandos DROP TABLE causava tempos de execução de vários minutos.
A classe WP_UnitTestCase resolve esta dificuldade recorrendo ao controlo de transações MySQL. Antes de executar cada método, o executor inicia uma transação. O teste executa as suas operações, insere artigos e altera definições. Na fase de encerramento (tearDown), o executor aplica um ROLLBACK, em vez de apagar os registos manualmente.
Este mecanismo de reversão proporciona vantagens imediatas:
- Cada teste inicia a sua execução num estado limpo e seguro da base de dados.
- A velocidade mantém-se elevada porque as alterações são descartadas em memória.
- Os valores de auto-incremento das chaves primárias continuam a progredir como num servidor ativo.
Em ambientes modernos com MySQL 8.0 ou MariaDB 10.11 sobre tabelas InnoDB, as transações oferecem uma base sólida e rápida para testes contínuos.
Ambientes locais estruturados com wp-env
Antigamente, a configuração de um ambiente de testes local exigia scripts de shell complexos, bases de dados locais e a obtenção de branches via Subversion. A ferramenta oficial @wordpress/env (wp-env) padroniza todo o processo através de contentores Docker.
O ficheiro de configuração .wp-env.json na raiz da extensão gere o ecossistema:
{
"core": "WordPress/WordPress#master",
"plugins": [ "." ],
"config": {
"WP_DEBUG": true,
"SCRIPT_DEBUG": true
},
"env": {
"tests": {
"config": {
"WP_DEBUG": true
}
}
}
}O comando wp-env start inicia os contentores do servidor web e do MySQL. Para executar os testes de integração no contentor dedicado, basta utilizar:
npx wp-env run tests-cli vendor/bin/phpunitO wp-env cria uma base de dados independente para testes, assegurando que os dados locais de desenvolvimento nunca são adulterados.
Testes de pontos finais da REST API e validação de esquemas
Os pontos finais personalizados da REST API constituem a base de soluções desacopladas, aplicações móveis e blocos interativos. Testes de integração para WP_REST_Controller validam o registo de rotas, permissões de acesso, esquemas de dados JSON e códigos de estado HTTP.
A classe WP_UnitTestCase comunica diretamente com o WP_REST_Server interno. Os pedidos são processados em memória, eliminando a latência de tráfego de rede.
<?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']);
}
}Verificar controladores REST garante que dados malformados são intercetados antes de atingirem a base de dados.
Validação de migrações e tabelas personalizadas
Muitos plugins avançados criam tabelas próprias para guardar registos de auditoria ou filas de tarefas em segundo plano. Confirmar que a criação de tabelas, alteração de campos e indexação ocorrem sem perda de dados requer testes de migração estruturados.
Nestes cenários avaliamos o comportamento de dbDelta() e a execução de comandos SQL atómicos.
<?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);
}
}Estes testes previnem avarias estruturais durante a atualização de versões em ambientes produtivos.
Testes de aceitação e automação de navegador com wp-browser
Os testes unitários e de integração correm no terminal, mas existem comportamentos que exigem verificação visual no navegador. Confirmar se as opções do painel de administração persistem após clicar em guardar ou se um formulário no checkout valida os campos no cliente requer testes de aceitação.
O wp-browser integra o ecossistema Codeception com as particularidades do WordPress, disponibilizando módulos práticos:
- WPDb: Permite consultar e manipular tabelas diretamente sem necessidade de bootstrap do PHPUnit.
- WPLoader: Carrega o WordPress para testes funcionais de módulos.
- WPWebDriver: Controla instâncias de Chrome ou Firefox através de Selenium ou Chromedriver.
<?php
// Teste de aceitação funcional com 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',
]);Os testes de aceitação cobrem toda a infraestrutura, assegurando total tranquilidade antes de cada publicação.
Testes em blocos Gutenberg com Jest e Playwright
O desenvolvimento moderno em WordPress junta lógica de backend em PHP a uma interface baseada em React. Por conseguinte, a verificação de blocos requer ferramentas do ecossistema JavaScript.
O pacote @wordpress/scripts define um ambiente padronizado. Lógica de utilitários e transformações de blocos são testadas em Jest, enquanto a experiência no editor é automatizada com o Playwright.
Validação de atributos e transformações com Jest
O Jest executa testes rápidos para componentes React e utilitários puros. A higienização de atributos e a gestão de versões obsoletas pertencem ao âmbito do 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);
});
});Testes de ponta a ponta no editor com Playwright
O Playwright gere um navegador headless, abre o editor Gutenberg, introduz blocos personalizados e verifica o estado do DOM e dos controlos laterais.
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');
});
});O Playwright impede que desvios de interface passem despercebidos aos testes de backend.
Análise estática com PHPStan em conjunto com o PHPUnit
A análise estática complementa os testes unitários. Enquanto os testes validam cenários específicos de entrada e saída, o PHPStan avalia todo o projeto para identificar inconsistências de tipos, código inativo e assinaturas incorretas antes de iniciar qualquer execução.
Através do pacote szepeviktor/phpstan-wordpress, o projeto passa a dispor de tipos rigorosos para a API do WordPress, evitando falhas ocultas tanto no código do plugin como nos próprios testes.
Ficheiro 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: falseExecutar vendor/bin/phpstan analyse no processo de integração contínua previne anomalias de execução antes do ciclo de testes.
Cobertura de código e requisitos de qualidade
Medir a cobertura de código faculta visibilidade sobre caminhos que ainda não foram avaliados. Ainda assim, impor um valor irrealista de cem por cento conduz frequentemente ao teste de métodos triviais em detrimento da lógica fundamental.
Equipas experientes definem uma meta realista entre 80% e 85% para a lógica de negócio, controlada no GitHub Actions através de PCOV ou Xdebug 3.
php -d pcov.enabled=1 vendor/bin/phpunit --testsuite=unit --coverage-text --coverage-html=coverage-reportConfigurar as exclusões no ficheiro XML do PHPUnit garante que bibliotecas de terceiros e vistas não influenciam os rácios de conformidade.
Integração contínua no GitHub Actions com PHP 8.2 e 8.3
Os testes automatizados revelam toda a sua utilidade quando são executados em cada commit e pull request. Este fluxo garante que nenhuma alteração é integrada sem validação nas versões suportadas de PHP.
Um fluxo moderno no GitHub Actions valida o código em PHP 8.2 e PHP 8.3 sobre 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=integrationA separação das etapas permite recolher o veredito dos testes unitários em menos de trinta segundos após o envio do código.
Organização de pastas para suites de testes
Uma estrutura arrumada estabelece claramente a fronteira entre testes unitários, testes de integração e testes de aceitação.
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.jsonConfiguração de phpunit.xml.dist para múltiplas suites
O ficheiro XML coordena os blocos de teste:
<?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>Esta configuração faculta a execução de testes unitários durante o desenvolvimento diário e a verificação integral antes da entrega final.
Matriz de testes e diretrizes de manutenção
A sustentabilidade dos testes assenta na regularidade dos processos e na revisão periódica da infraestrutura.
| Nível de teste | Ferramentas | Duração típica | Dependência de base de dados | Foco principal |
|---|---|---|---|---|
| Testes unitários | PHPUnit 10/11, Brain Monkey, Mockery | Milissegundos | Nenhuma (Memória) | Lógica pura, operações de cálculo, filtros |
| Testes de integração | WP_UnitTestCase, wp-env | Segundos | Base de testes MySQL | Consultas WP_Query, persistência, prioridades |
| Testes de aceitação | wp-browser, Codeception | Segundos a minutos | Navegador headless + DB | Configurações no wp-admin, privilégios, checkout |
| Testes de blocos e2e | Playwright, @wordpress/scripts | Minutos | Ambiente Docker | Editor Gutenberg, controlos de bloco, markup |
Boas práticas essenciais:
- Garantir isolamento: Evitar chamadas a bases de dados no diretório de testes unitários.
- Aproveitar reversões: Acelerar testes de integração anulando transações.
- Monitorizar na CI: Validar cada branch em PHP 8.2 e 8.3.
- Inspecionar blocos: Confirmar que novas versões do Gutenberg preservam o conteúdo existente.
- Refatorar para testar: Desacoplar algoritmos de domínio das vistas do WordPress.
Consulte mais detalhes sobre arquitetura e os nossos serviços de programação WordPress profissional na WPPoland.
Cuidados com internacionalização e extensões externas
Em projetos globais, as extensões interagem habitualmente com soluções multilingues como o Polylang ou WPML e ferramentas de comércio como o WooCommerce. A carência de testes nas rotinas de localização pode causar a apresentação de mensagens em idiomas incorretos nas comunicações por e-mail ou no carrinho.
Nos testes unitários de internacionalização deve simular-se as funções de tradução com o Brain Monkey, garantindo que marcadores de posição mantêm a estrutura exigida:
<?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('Encomenda #%d concluída');
$translator = new Translator();
$message = $translator->formatOrderMessage(105);
$this->assertSame('Encomenda #105 concluída', $message);
}
}Nos testes de integração monitoriza-se o filtro locale para impedir que trocas de idioma em tempo de execução provoquem caches residuais inválidas.
Diagnóstico e análise de testes com execução demorada
À medida que o repositório acumula novos ficheiros de teste, a duração global das execuções torna-se um fator determinante no dia a dia da equipa. O PHPUnit faculta ferramentas de diagnóstico dedicadas à identificação de métodos excessivamente lentos.
Com a opção --profile, os programadores conseguem inspecionar rapidamente quais as rotinas que requerem atenção:
vendor/bin/phpunit --testsuite=integration --profileQuando um teste de integração excede os 200 milissegundos, a origem reside quase sempre na falta de índices em tabelas temporárias do MySQL, em árvores de hooks excessivamente profundas ou em leituras repetidas de ficheiros XML sem cache.







