Gutenberg 仓库 PHP 测试(PHPUnit)实战指南:Agent 规则、环境路由与函数前缀测试
2026/9/15 10:21:05 网站建设 项目流程

Gutenberg 仓库 PHP 测试(PHPUnit)实战指南:Agent 规则、环境路由与函数前缀测试

【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg

本篇技术指南聚焦 WordPress 块编辑器项目 Gutenberg 仓库中的PHP 测试(PHPUnit)体系:从 AI Agent 运行 PHP 测试时的规则约定、wp-env 测试环境的启动与状态检查,到composer test/vendor/bin/phpunit的具体执行方式,再到测试内置(带前缀)PHP 函数这一仓库特有的关键约束。读完本文,你将掌握在 Gutenberg 仓库中正确启动、路由、编写与运行 PHPUnit 测试的完整流程,并能依据源码与配置逐层理解其底层原理。

关联文档与适用范围

本指南的主体依据是仓库中的 .agents/skills/testing/references/php.md,它是.agents/skills/testing技能(SKILL.md)针对PHP 测试(PHPUnit)的场景化路由文件。该技能整体覆盖三类测试:JavaScript 单元/集成测试(Jest,见 references/jest.md)、PHP 测试(PHPUnit,即本文主题)、端到端测试(Playwright,见 references/e2e.md)。

php.md 明确声明其适用对象是Agent(AI 编码代理),因此内容强调"规则(rules)与路由(routing)":什么时候能跑、跑什么命令、测试哪些符号、遵守哪些红线。这些约定同样适用于任何在本地复现 PHP 测试流程的开发者。

运行 PHP 测试的前提:wp-env 测试环境

php.md 开门见山给出最重要的一条 Agent 规则:PHPUnit 测试依赖 wp-env 测试环境。流程必须是:

# 1. 先检查环境是否已在运行 npm run wp-env-test status # 2. 仅当环境未运行时才启动 npm run wp-env-test start

这条规则在仓库根目录的 AGENTS.md 中被完整复述:"Always check status first. Only start if not already running."(先检查状态,仅在未运行时启动)。对于 Agent 会话而言,反复start会浪费大量时间并可能触发端口冲突,因此"先 status 再 start"是硬性约定。

从 package.json 可以看到wp-env-test脚本的实际定义:

"wp-env-test": "wp-env --config .wp-env.test.json"

即所有 wp-env 相关操作都使用独立的测试环境配置 .wp-env.test.json,其关键配置包括:

  • port: 8889:测试环境专用端口,与开发环境(默认 8888)隔离;
  • core: "WordPress/WordPress":拉取 WordPress 核心用于测试;
  • plugins: ["."]:将当前 Gutenberg 仓库作为插件挂载;
  • themesmappings:挂载测试主题(./test/emptythemegutenberg-test-themes等)和测试用 mu-plugins、测试插件,确保测试运行在接近真实站点的环境中。

为什么 PHP 测试必须依赖 wp-env

Gutenberg 的 PHP 测试继承自 WordPress Core 的 PHPUnit 测试体系,需要一个完整的 WordPress 环境(数据库、核心函数、主题/插件加载机制)才能真正执行。这一点可以从测试引导文件 phpunit/bootstrap.php 得到印证:

  • 定义WP_DEBUGLOCAL_WP_DEBUG_LOG等调试常量(第 9-23 行),与 WordPress Core 的 PHPUnit 测试保持一致性;
  • 通过WP_TESTS_DIR环境变量或回退路径定位 WP 测试库(第 36-49 行);
  • 通过_manually_load_plugin()手动加载被测插件lib/load.php(第 61-64 行);
  • 注册fail_if_died处理wp_die,避免 WordPress 在测试启动阶段静默死亡导致"假通过"(第 78-85 行);
  • 通过$GLOBALS['wp_tests_options']预启用一批实验特性(gutenberg-full-site-editinggutenberg-dashboard-widgetsgutenberg-real-time-collaboration等,第 87-97 行),使测试能覆盖实验性代码路径。

执行 PHP 测试的两条命令

php.md 给出的运行方式有两条:

# 方式一:运行全部 PHP 测试(含 lint) composer test # 方式二:运行指定测试文件或目录 vendor/bin/phpunit <path_to_test_file.php>

composer test 到底做了什么

composer.json 的 scripts 定义如下:

"scripts": { "format": "phpcbf --standard=phpcs.xml.dist --report-summary --report-source", "lint": "phpcs --standard=phpcs.xml.dist", "test": "phpunit", "test:watch": "phpunit-watcher watch < /dev/tty" }

也就是说composer test直接调用phpunit(使用根目录 phpunit.xml.dist 配置),而composer run test:watch则使用sirbrillig/phpunit-watcher(composer.json 的 require-dev 中包含spatie/phpunit-watcher)实现文件变更自动重跑。

值得注意的是:composer test只跑 PHPUnit,不包含代码风格检查。composer.json 中的lint脚本(phpcs --standard=phpcs.xml.dist)才是 PHP_CodeSniffer 的 PHP 代码规范检查,format脚本(phpcbf)用于自动修复。这与"PHP 测试 + lint"一体化的 npm 命令(见下文)有区别。

vendor/bin/phpunit 直接调用

第二种方式是直接调用 Composer 安装的 PHPUnit 二进制,<path_to_test_file.php>可以是单个测试文件,也可以是目录。例如:

vendor/bin/phpunit phpunit/block-supports/anchor-test.php vendor/bin/phpunit phpunit/block-supports/

通过 npm scripts 运行(仓库的完整链路)

虽然 php.md 只给了 composer 两条命令,但仓库在 package.json 中封装了更完整的 npm 链路,理解它有助于把握"composer test"之外的全貌:

"test:php": "npm run lint:php && npm run test:unit:php", "test:unit:php:setup": "wp-env --config .wp-env.test.json start", "test:unit:php:base": "wp-env --config .wp-env.test.json run --env-cwd='wp-content/plugins/gutenberg' wordpress vendor/bin/phpunit -c phpunit.xml.dist --verbose", "test:unit:php": "npm run test:unit:php:setup && npm run test:unit:php:base", "test:php:watch": "wp-env --config .wp-env.test.json run --env-cwd='wp-content/plugins/gutenberg' cli composer run-script test:watch"

对照 docs/contributors/code/testing-overview.md 的 PHP testing 一节可以看到官方文档的表述:

  • npm run test:php:同时执行 PHP lint(PHP_CodeSniffer)与 PHPUnit 单测;
  • npm run test:unit:php:只跑单测、跳过 linter;
  • npm run test:php:watch:文件变更自动重跑(类似 Jest watch);
  • npm run lint:php:独立做 PHP 代码规范检查。

官方文档同时提示:这些 phpunit 命令要求 wp-env 正在运行且 composer 依赖已安装;npm 脚本会自动为你启动 wp-env(对应test:unit:php:setup),而 php.md 之所以要求先手动status/start,是为了让 Agent 对环境的生命周期有显式控制、避免反复启停。

从 wp-env 视角理解 PHPUnit 的执行位置

一个值得注意的实现细节:test:unit:php:base使用wp-env ... run --env-cwd='wp-content/plugins/gutenberg' wordpress vendor/bin/phpunit,这意味着 PHPUnit 是在wp-env 容器内部的 WordPress 环境中执行的,工作目录是插件挂载点wp-content/plugins/gutenberg。这正好呼应了 bootstrap.php 中"如果运行在 WP 的 build 目录中则声明WP_RUN_CORE_TESTS"(第 31-33 行)的逻辑,也解释了为什么vendor/bin/phpunit必须在容器内可访问——Composer 依赖安装于插件根目录。

在 CI 侧,.github/workflows/unit-test.yml 展示了同样的模式:先运行npm run wp-env-test -- run wordpress ... vendor/bin/phpunit -- --version校验 PHPUnit 可用,再分别执行npm run test:unit:php(单站点)与npm run test:unit:php:multisite(多站点),最后通过解析输出中的OK (N testsTests: N, Assertions:来判定通过与否。

测试目录结构与命名约定

Gutenberg 的 PHP 测试集中在 phpunit/ 目录,其组织与 phpunit.xml.dist 的 testsuite 声明一一对应:

<testsuites> <testsuite name="default"> <directory suffix="-test.php">./phpunit/</directory> <directory suffix=".php">./phpunit/tests/</directory> <directory suffix=".php">./phpunit/blocks/</directory> </testsuite> </testsuites>

关键约定:

  • 根级测试文件(如phpunit/class-wp-theme-json-test.phpphpunit/class-wp-duotone-test.php)以-test.php结尾;
  • 子目录测试phpunit/tests/phpunit/blocks/)以.php结尾即被收集;
  • 组排除ms-required(仅多站点可运行)与fontsapi(字体 API 实验特性)两个组在单站点运行时被排除,避免环境不匹配导致误报。

相应地,phpunit/multisite.xml 是面向 WordPress 多站点(Multisite)的独立配置:它通过<env name="WP_MULTISITE" value="1" />开启多站点模式,排除ms-excludedfontsapi组。npm 侧对应的命令是npm run test:unit:php:multisite(见 package.json)。单站点与多站点是两套独立运行通道,改动涉及多站点行为(如is_multisite()分支、grant_super_admin等)时必须同时跑两套。

一个真实的测试文件解剖

以 phpunit/block-supports/anchor-test.php 为例,可以看到仓库 PHP 测试的典型写法:

/** * @covers ::gutenberg_register_anchor_support * @dataProvider data_gutenberg_register_anchor_support */ public function test_gutenberg_register_anchor_support( bool $support, ?array $value, array $expected ) { // ... gutenberg_register_anchor_support( $block_type ); } public function data_gutenberg_register_anchor_support(): array { // 返回多组 (support 配置, 属性值, 期望输出) 组合 }

要点:

  • 测试类继承WP_UnitTestCase(如 phpunit/class-wp-theme-json-test.php),获得 WordPress 测试工厂(self::factory()->user->create()等)与完整事务回滚;
  • 大量使用@dataProvider做参数化测试,覆盖边界值与多分支;
  • 使用@covers注解标明被测函数/类,便于生成覆盖率报告。

核心约束:测试"内置(带前缀)函数"而非源码函数

php.md 将 Testing prefixed functions 列为重点深读内容,并提示前缀规则本身的完整描述位于根目录 AGENTS.md 的 pitfalls 中。这是 Gutenberg PHP 测试最容易踩坑、也最具仓库特色的规则。

前缀机制的原理

Gutenberg 插件的 PHP 代码在构建时会被自动改名,以避免与 WordPress Core 的函数/类重名冲突。相关机制详见 docs/contributors/code/build-system-function-prefixing.md:

符号类型源码写法(开发时)构建后(运行时实际存在)
函数名block_core_navigation_link_build_css_colors()gutenberg_block_core_navigation_link_build_css_colors()
函数调用wp_get_typography_font_size_value()gutenberg_get_typography_font_size_value()
类名WP_Style_EngineWP_Style_Engine_Gutenberg

构建产物输出到build/目录,lib/blocks.php按优先级加载这些内置文件。因此运行时真正被调用的是带前缀的名字,测试也就必须调用这些带前缀的名字,否则会触发"函数不存在"错误或测试到错误的代码版本。

测试必须调用内置名称

Testing Prefixed Functions 给出了明确示例(测试文件位于phpunit/blocks/):

class My_Block_Test extends WP_UnitTestCase { public function test_my_function() { // 测试内置函数(带 gutenberg_ 前缀) $result = gutenberg_block_core_my_block_render_function( $args ); $this->assertEquals( $expected, $result ); } public function test_my_class() { // 测试内置类(带 _Gutenberg 后缀) $handler = new WP_Example_Block_Handler_Gutenberg(); $result = $handler->process( $input ); $this->assertEquals( $expected, $result ); } }

仓库中这样的例子俯拾皆是。例如 phpunit/block-supports/anchor-test.php 直接调用gutenberg_register_anchor_support()gutenberg_apply_anchor_support();phpunit/block-supports/block-style-variations-test.php 则实例化WP_Theme_JSON_Resolver_GutenbergWP_Theme_JSON_Gutenberg_Gutenberg后缀类;phpunit/class-wp-theme-json-test.php 在类注释中直接以@covers WP_Theme_JSON_Gutenberg声明被测类。

反向场景:回迁到 WordPress Core 时

文档同时给出了一条重要例外:如果测试被回迁(backport)到 WordPress Core,则必须改回测试无前缀版本(block_core_my_block_render_functionWP_Example_Block_Handler)。这正是前缀机制设计目标之一——Gutenberg 可以独立于 Core 发布周期演进,而代码回迁后只需去掉前缀即可复用。

Agent 测试写作规范(通用红线)

虽然 php.md 本身很短,但它隶属于.agents/skills/testing/SKILL.md技能体系,其中的通用规则对 PHP 测试同样适用,且与 PHP 代码评审(phpcs)直接相关:

  1. 先与作者确认测试清单:动笔前先拟出测试用例名(从用户视角描述行为,一条用例对应一个行为),与作者确认后再写测试体;无人值守时把清单写进总结供评审。对应文档规范见 Testing Overview 的 "Describing tests"。
  2. 禁止通过削弱测试来让失败变绿:不放松断言、不无端增加等待/超时、不静默跳过用例。要么诊断根因,要么如实报告失败。
  3. 禁止为了修测试而改生产代码,除非生产代码本身就是 Bug 源:测试通过不是任务完成的最终标准,验证生产代码按预期工作才是核心目标。
  4. 代码规范同样适用:Gutenberg 的 PHP 测试代码与生产代码同等对待(testing-overview.md 明确"Tests are also part of our code base")。仓库提供了专用的编码标准包 test/php/gutenberg-coding-standards(作为 path 仓库被 composer.json 引用为gutenberg/gutenberg-coding-standards),配合wp-coding-standards/wpcsphpcompatibility/phpcompatibility-wp等依赖,通过vendor/bin/phpcs/vendor/bin/phpcbf强制执行。

快速上手清单(Agent 与开发者通用)

综合 php.md 与仓库配置,一次规范的 PHP 测试会话可以归纳为以下步骤:

  1. 准备依赖npm install && composer install(安装 Node 与 PHP 依赖,含 PHPUnit、PHP_CodeSniffer、编码标准包)。
  2. 检查环境npm run wp-env-test status;若未运行则npm run wp-env-test start
  3. 运行测试
    • 全部 PHP 测试(仅 PHPUnit):composer test
    • 指定文件/目录:vendor/bin/phpunit phpunit/block-supports/
    • 全链路(lint + 单测):npm run test:php
    • 仅单测:npm run test:unit:php
    • 多站点:npm run test:unit:php:multisite
    • 监听模式:npm run test:php:watch
  4. 遵守符号约定:测试中一律调用构建后的gutenberg_*函数与*_Gutenberg类;若面向 Core 回迁则使用无前缀版本。
  5. 风格检查composer run lint(检查)与composer run format(自动修复),或直接vendor/bin/phpcs/vendor/bin/phpcbf
  6. CI 对齐:本地应同时通过单站点与多站点两套 PHPUnit(对应 .github/workflows/unit-test.yml 的 CI 流水线),并保持 PHP 代码符合 WordPress Coding Standards。

总结

.agents/skills/testing/references/php.md用极简篇幅划定了 Gutenberg 仓库 PHP 测试的关键路径:wp-env 测试环境先行、composer test/vendor/bin/phpunit执行、前缀函数测试约定、以及指向 Testing Overview 的深度文档路由。其背后是仓库完整的工程化支撑——phpunit.xml.dist的测试套件编排、bootstrap.php的 WordPress 测试环境引导、composer/npm 双通道命令封装、以及构建期函数前缀机制。对 Agent 而言,这些约定确保了测试行为的确定性(不反复启停环境、不改弱断言、不误改生产代码);对开发者而言,它们就是一份可直接落地的 PHPUnit 实战手册。

【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询