Skip to content

Chore: Upgrade PHPUnit to 12, modernize tests, refresh Rector sets#248

Merged
loks0n merged 4 commits intomainfrom
chore/upgrade-phpunit-12
Apr 24, 2026
Merged

Chore: Upgrade PHPUnit to 12, modernize tests, refresh Rector sets#248
loks0n merged 4 commits intomainfrom
chore/upgrade-phpunit-12

Conversation

@loks0n
Copy link
Copy Markdown
Contributor

@loks0n loks0n commented Apr 24, 2026

Summary

  • Upgrade phpunit/phpunit ^9.5 → ^12.0, phpstan/phpstan ^2.0 → ^2.1, rector/rector ^2.0 → ^2.4 (all pulling the current latest).
  • Expand Rector with the PHPUnit 10/11/12, code-quality, and annotations-to-attributes sets; drop three dead skip entries; skip AssertEmptyNullableObjectToAssertInstanceofRector which weakens assertNull.
  • Run the refactor (adds declare(strict_types=1) to tests, finalizes test classes, converts the @dataProvider to a generator, assertEqualsassertSame where inferable) and sweep remaining assertEquals(null|true|false, …) and literal-expected cases manually.
  • Migrate phpunit.xml to the PHPUnit 12 schema and exclude the BaseTest trait file and the misnamed UtopiaFPMRequestTest mock helper from the unit suite (both previously produced runner warnings).

Noteworthy fixes surfaced by stricter assertions

  • RequestTest::testCanRemoveHeaders asserted assertEquals(null, getHeader(...)), which only passed via null == '' loose equality — getHeader is typed string. Now assertSame('', …).
  • RouteTest::testCanSetAndGetAction compared two different closures with assertEquals — replaced with assertInstanceOf(\Closure::class, …), which is what the test actually meant.

Test plan

  • composer analyze (PHPStan level 7) clean
  • composer refactor:check (Rector dry-run) clean
  • composer format:check (Pint) clean
  • vendor/bin/phpunit --testsuite unit — 84 tests, 248 assertions, all pass
  • e2e suites (e2e-fpm, e2e-swoole) — require docker fixtures, not run locally; CI should exercise them

🤖 Generated with Claude Code

- Bump phpunit/phpunit ^9.5 -> ^12.0, phpstan/phpstan ^2.0 -> ^2.1, rector/rector ^2.0 -> ^2.4.
- Migrate phpunit.xml to the PHPUnit 12 schema; exclude the BaseTest trait and
  the misnamed UtopiaFPMRequestTest mock helper from the unit suite.
- Add PHPUnit 10/11/12, code-quality, and annotations-to-attributes sets to
  rector.php; drop three skip entries rector reported as unregistered; skip
  AssertEmptyNullableObjectToAssertInstanceofRector since it weakens assertNull.
- Apply rector: declare(strict_types=1) in tests, final test classes, generator
  data provider, and assertEquals -> assertSame where types are inferable.
- Manual cleanup: assertEquals(null|true|false, x) -> specific methods; fix
  RequestTest::testCanRemoveHeaders which relied on null == '' loose equality
  (getHeader returns string); replace closure-vs-closure assertEquals in
  RouteTest::testCanSetAndGetAction with assertInstanceOf(Closure::class, ...).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 24, 2026

k6 benchmark

Throughput Requests Fail rate p50 p95
5490 req/s 384358 0% 7.51 ms 15.54 ms

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 24, 2026

Greptile Summary

This PR upgrades PHPUnit 9 → 12, PHPStan 2.0 → 2.1, and Rector 2.0 → 2.4, then applies the resulting automated and manual test modernisation: declare(strict_types=1), final classes, #[DataProvider] attributes, and assertEqualsassertSame conversions throughout. The PHPUnit 12 schema, suite exclusions, and Rector skip-list are all handled correctly.

  • P1 — tests/ResponseTest.php testCanAddCookie: The "cookie case insensitive" block assigns to PHP array copies ($result->getCookies()['cookiename']['name'] = ...) which are immediately discarded, so the case-normalisation behaviour is silently never verified.

Confidence Score: 4/5

Safe to merge after addressing the dead-assignment bug in testCanAddCookie that leaves cookie case-normalisation completely untested.

One P1 finding: the cookie case-insensitive test block in ResponseTest.php mutates throwaway array copies instead of asserting, meaning the case-normalisation path is never exercised. The remaining findings are P2 style (assertEquals → assertSame completeness in HttpTest and the e2e suite).

tests/ResponseTest.php — testCanAddCookie dead-assignment block (lines 70–73)

Important Files Changed

Filename Overview
tests/ResponseTest.php Migrated to final class, strict_types, assertSame for fluent return values — but the cookie case-insensitive block (lines 72–73) contains dead assignments instead of assertions, silently leaving the case normalization behavior unverified.
tests/HttpTest.php Migrated to final class, strict_types, @dataProvider → #[DataProvider] attribute, and most assertEquals → assertSame; one assertEquals on JSON strings remains on line 682.
tests/RequestTest.php Migrated cleanly: strict_types, final class, assertEquals(null) → assertSame('') fix for getHeader after removeHeader.
tests/RouteTest.php Migrated cleanly: strict_types, final class, two-closure assertEquals replaced with assertInstanceOf(Closure::class) + behavioral assertion.
tests/e2e/ResponseFPMTest.php Gets strict_types and final class; five assertEquals calls on string cookie values remain unconverted to assertSame.
phpunit.xml Migrated to PHPUnit 12 schema with xsi:noNamespaceSchemaLocation; BaseTest.php and UtopiaFPMRequestTest.php correctly excluded from unit suite to suppress runner warnings.
rector.php Expanded with PHPUnit 10/11/12 sets, code-quality, and annotations-to-attributes; dead skips removed; AssertEmptyNullableObjectToAssertInstanceofRector correctly skipped with rationale.
composer.json Bumps phpunit ^9.5 → ^12.0, phpstan ^2.0 → ^2.1, rector ^2.0 → ^2.4 as intended.

Comments Outside Diff (1)

  1. tests/ResponseTest.php, line 70-73 (link)

    P1 The "test cookie case insensitive" block assigns to throwaway array copies rather than asserting anything. In PHP, getCookies() returns an array by value, so writing to $result->getCookies()['cookiename']['name'] modifies a temporary copy that is immediately discarded. The case-insensitive storage of cookieNamecookiename is never actually verified.

Reviews (3): Last reviewed commit: "Chore: Add PHPUnit schema reference, tig..." | Re-trigger Greptile

Comment thread phpunit.xml Outdated
Comment thread tests/HttpTest.php Outdated
loks0n and others added 3 commits April 24, 2026 12:54
The CI e2e-swoole job failed because appwrite/base:0.5.0 ships PHP 8.2.6,
but PHPUnit 12 requires PHP >= 8.3. Bumping to 1.2.0 (PHP 8.5.4, swoole
included) matches the library's >=8.3 floor and the host test runtime.

Drop the now-redundant curl_close() call in tests/e2e/Client.php — PHP 8.5
deprecates it (the handle is released on last reference since 8.0 anyway).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PHPUnit 12 requires a <source> section for coverage to run; without it the
runner emits "No filter is configured, code coverage will not be processed"
and CI's --coverage-* flags exit non-zero. Point coverage at ./src.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- phpunit.xml: add xmlns:xsi and xsi:noNamespaceSchemaLocation pointing at
  vendor/phpunit/phpunit/phpunit.xsd so PHPUnit 12 (and IDE tooling) get
  XML schema validation.
- HttpTest: swap reversed assertEquals(actual, expected) pairs in
  testCanSetRoute, testCanMatchRoute, and testCanMatchFreshRoute to the
  expected-first convention, and promote them to assertSame — setRoute
  and match return the exact Route instance, so identity is the precise
  check and the diff on failure reads correctly.
- ResponseTest: promote fluent-interface assertions on addHeader /
  addCookie to assertSame for the same reason.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@loks0n loks0n merged commit d1eced0 into main Apr 24, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant