lchrusciel/api-test-case
ApiTestCase is a PHPUnit TestCase for Symfony API development, extending WebTestCase with JSON/XML response matching via PHP-Matcher and optional Alice/Doctrine fixture loading. It supports a clear TDD workflow, readable assertion errors, and simple expected-response files.
Framing correction (material to the decision): the brief asks for an assessment as a Laravel/PHP package, but lchrusciel/api-test-case is a Symfony-only package. It extends Symfony\Bundle\FrameworkBundle\Test\WebTestCase and drives assertions through Symfony's KernelBrowser ($this->client->request(...), $this->client->getResponse()). Laravel's test harness (Illuminate\Foundation\Testing\TestCase, MakesHttpRequests, assertJson*) is a separate lineage; there is no adapter here. That single fact dominates the architecture-fit assessment below.
Architecture fit
WebTestCase that adds value in three places: (1) response-body assertions against a checked-in expected-response file with a real diff, (2) coduo/php-matcher pattern placeholders (@string@, @integer@, @[email protected](), UUID matcher added in #149) so volatile values (id, created_at, uuid) don't make tests brittle, (3) optional Alice/Doctrine fixture loading and DB purging.coduo/php-matcher is framework-agnostic and can be wrapped in a Laravel test trait or custom assertJsonMatches() in roughly a day.IS_DOCTRINE_ORM_SUPPORTED and two bundles registered only in the test environment, so a non-Doctrine or non-fixture-using app pays no cost.TestCase and Symfony's WebTestCase. Every PHPUnit major and Symfony major is therefore a potential breaking event for this package — visible in the release history (v5.3.0 dropped Symfony 5.4/6.1–6.3; v5.3.2 dropped 5.4 and added 6.4/7.0; v5.3.3 added PHPUnit 11). Consumers inherit that treadmill.Integration feasibility
composer require --dev lchrusciel/api-test-case is documented as working with zero configuration, with sane directory guessing (../Responses relative to the test class, ../DataFixtures/ORM/).phpunit.xml <server> entries (KERNEL_CLASS, EXPECTED_RESPONSE_DIR, FIXTURES_DIR, TMP_DIR, OPEN_ERROR_IN_BROWSER, ESCAPE_JSON). No service container changes, no production code, no migrations.Technical risk
lchrusciel). 410 stars and 0 dependents reported means we would be among the first real consumers outside the Sylius/Lakion orbit — low evidence of production hardening at scale.ESCAPE_JSON exists purely for backwards compatibility and is slated for removal — a future breaking change we'd inherit).OPEN_ERROR_IN_BROWSER=true in a CI environment; undocumented $client initialization expectations; tearDown visibility change (#152) that can break subclass overrides.Key questions for the team
hautelook/alice-bundle/DAMA\DoctrineTestBundle? Bundle and fixture-loader overlap needs resolving before adoption.league/openapi-psr7-validator, mnapoli/silly-style contract tests) may be a better long-term investment than golden files — and would make this package redundant.Stack fit
coduo/php-matcher (bundled transitively), and only if using fixtures: nelmio/alice + fidry/alice-data-fixtures, both registered ['test' => true] in config/bundles.php.coduo/php-matcher plus a custom base test case extending Illuminate\Foundation\Testing\TestCase, replacing assertResponse($response, 'file') with assertJsonMatchesFile(TestResponse $response, string $file). Treat that as a ~1–2 day spike, not a package adoption.Migration path (Symfony)
require-dev dependency; verify composer resolution against current symfony/framework-bundle, phpunit/phpunit, doctrine/orm.KERNEL_CLASS, EXPECTED_RESPONSE_DIR, FIXTURES_DIR, TMP_DIR explicitly in phpunit.xml rather than relying on directory guessing — the implicit defaults are the most common source of "works locally, fails in CI."GET /products endpoint). Write the expected response first, confirm the red-green loop and the diff output actually help developers.App\Tests\ApiTestCase) so the third-party base is referenced in exactly one place — this is the cheapest possible future migration lever.Compatibility checks before commit
KernelTestCase base, PantherTestCase, symfony/panther)? Conflicting base classes are the usual integration failure.DAMA\DoctrineTestBundle (transaction wrapping) conflict with the package's own DB purger? Decide on one isolation strategy.paratest) and TMP_DIR/fixture purging: confirm isolation before scaling the suite.Sequencing
Maintenance
ESCAPE_JSON flag is documented as a backwards-compatibility shim scheduled for removal — expect one future breaking change on the JSON escaping path.Support
Scaling
TMP_DIR per worker and a DB strategy that tolerates concurrency; validate early, not at 500 tests.@array@ everywhere) silently weakens the suite — this needs a code review rule, not tooling.Failure modes (ranked by likelihood × cost)
EXPECTED_RESPONSE_DIR / FIXTURES_DIR unset locally works, CI fails. Mitigate by setting all env vars explicitly.OPEN_ERROR_IN_BROWSER=true in CI — attempts to launch a browser, hangs or errors in headless runners. Explicitly set false for CI.RunTimeException when the fixtures directory is empty or missing; intermittent failures under parallel execution. Mitigate with explicit purger strategy.NelmioAliceBundle / FidryAliceDataFixturesBundle not registered for test, producing confusing container errors. Covered by the pilot if fixtures are exercised in Phase 1.tearDown() override conflicts — any subclass overriding tearDown must respect the protected visibility change; a small but easy-to-hit trap.Ramp-up
@[email protected](), @uuid@, @array@) is a small DSL that must be documented in the repo's testing guide, along with the "where do expected responses live" convention. Inconsistent placement is the most common onboarding error.TPM recommendation
require-dev, timeboxed to a one-controller pilot, gated on an explicit phpunit.xml config and a named internal owner. Value is real and the blast radius is contained.coduo/php-matcher behind an internal assertJsonMatchesFile() helper, capturing the same developer ergonomics with zero third-party framework coupling.How can I help you explore Laravel packages today?