wpmedia-phpunit binary breaks @runInSeparateProcess tests

Đang mở
#51 3 bình luận 0 reaction 1 người được giao Xem trên GitHub

@remyperona đang làm issue này rồi.

Từ ngày 18/8/2026.

  • #54 của @remyperona — đã đóng, không merge

Đánh giá

Issue này chưa được đánh giá.

Mô tả

bug Made by AI

🤖 AI-generated — created with Claude Code, reviewed by @Tabrisrp. Discovered while migrating wp-media/mcp-oauth to wp-media/phpunit v3.2.

Summary

The wpmedia-phpunit binary is incompatible with PHPUnit's @runInSeparateProcess isolation: all @runInSeparateProcess tests fail when run through the binary, while identical tests pass under a direct vendor/bin/phpunit invocation with the same arguments.

Steps to reproduce / Evidence

Reproduction in a consumer plugin (wp-media/mcp-oauth):

  • A test class with 9 @runInSeparateProcess + @preserveGlobalState disabled data sets
    • Via composer test-unit (runs wpmedia-phpunit unit): 0/9 pass (Test was run in child process and ended unexpectedly)
    • Via direct vendor/bin/phpunit --testsuite unit --colors=always --configuration Tests/Unit/phpunit.xml.dist: 9/9 pass
    • Same effective arguments; identical test code

PHPUnit instrumentation evidence:

  • Instrumenting vendor/phpunit/phpunit/src/Util/PHP/Template/TestCaseMethod.tpl with counters showed the isolated child dies inside the {included_files} block: the included-file count grows from 58 → 142 in the passing (direct) run, whereas the binary-run child never survives that block to reach the configured bootstrap require.

Root cause

The binary (wpmedia-phpunit at repo root) and src/BootstrapManager.php bootstrap PHPUnit by require-ing vendor/bin/phpunit into the currently running PHP process (see BootstrapManager::runTestSuite(), the require_once "{$root}/bin/phpunit" line).

The failure chain:

  1. wpmedia-phpunit and src/BootstrapManager.php are added to get_included_files() when loaded into the parent process.
  2. For @runInSeparateProcess tests, PHPUnit serializes the parent's included-files list into each child and re-requires them (PHPUnit\Util\GlobalState::getIncludedFilesAsString()).
  3. The child re-requires wpmedia-phpunit.
  4. Because that script begins with a #!/usr/bin/env php shebang and, when included, self-executes (it calls BootstrapManager::setupConstants() and BootstrapManager::runTestSuite() at the top level), re-including it in the child re-runs the whole bootstrap manager and emits the shebang line to the child's STDOUT.
  5. That corrupts the serialized child result the parent reads back → Test was run in child process and ended unexpectedly.
  6. Every isolated data set fails.

A direct vendor/bin/phpunit run passes because its included files are all inert library files — harmless to re-require.

Proposed fix

Two options; the second is recommended as the robust, long-term solution.

Option 1 — Minimal / targeted

In BootstrapManager, before running the suite, register the binary entrypoints into PHPUnit's isolation exclusion list so they are not re-required in isolated children:

$GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'][] = realpath( $wpmedia_phpunit_binary_path );
$GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'][] = realpath( __DIR__ . '/BootstrapManager.php' );

PHPUnit already honors this list in vendor/phpunit/phpunit/src/Util/GlobalState.php (getIncludedFilesAsString() skips listed files). Composer's bin-proxy already populates it for the real phpunit entry; the binary's own entrypoints simply need to be added.

  • Pros: minimal change; reuses PHPUnit's existing mechanism.
  • Cons: does not address the structural issue of loading PHPUnit into-process.
Option 2 — Structural / robust (recommended)

Run PHPUnit as a genuine subprocess (proc_open/passthru) instead of require-ing it into the runner process, so the binary and BootstrapManager never enter the test process's included-files set at all. This mirrors how native phpunit runs.

  • Pros: eliminates the root cause; robust against future PHPUnit versions and other edge cases.
  • Cons: larger refactor; requires careful subprocess lifecycle/error handling.

Impact

  • @runInSeparateProcess is common in WordPress plugin tests (e.g. tests that define() constants such as WP_DEBUG / WP_DEBUG_LOG). Affected consumers cannot use the README-recommended wpmedia-phpunit binary and must fall back to direct phpunit.
  • Dogfooding/README inconsistency worth noting: the README recommends "test-unit": "wpmedia-phpunit unit", but this library's own composer.json scripts invoke vendor/bin/phpunit --configuration ... directly — i.e. they sidestep the binary and therefore this bug.

Additional notes

Minor related papercut: BootstrapManager::getConfigArgv() hardcodes --colors=always, which emits raw ANSI escape codes when output is piped to a non-TTY (CI logs / file capture). Consider --colors=auto or making it overridable.

Ngôn ngữ chính
PHP
Star
4
Fork
2
Merge trung bình
3 ngày 7 giờ
Pull request đã merge (30 ngày)
5

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của wp-media/phpunit

Tất cả issue của wp-media/phpunit

Issue tương tự

Thêm issue về PHP

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.