mekras/symfony-bundle-testing
Testing utilities for Symfony bundles: helpers for booting test kernels, configuring services, and writing functional and integration tests around your bundle code. Simplifies PHPUnit setup so you can focus on assertions.
Architecture fit. Version 0.3.0 pivots the package from a set of implicit, test-case-inherited helpers toward an explicit builder abstraction (TestContainerBuilder). This is a sound architectural direction: it separates container construction (loading extensions, registering bundles, toggling public visibility) from the assertion/consumption surface, which makes the test harness composable and mockable. For a Laravel shop, the direct fit is low — the package is Symfony KernelTestCase-oriented (registerBundle, loadExtension, service locators) and has no Laravel service-provider equivalent. Its value to us is primarily as a pattern reference for how to test our own Laravel service providers and container bindings, not as a dependency.
Integration feasibility. Two distinct questions must be separated:
makePublic() / makeLocatable() / expectDefinitionsExists() vocabulary maps cleanly onto Laravel concepts ($app->bind, app()->make, assertInstanceOf), and we can mirror the builder API in our own test support package without taking the dependency.Technical risk.
createContainer() and createContainerFromFile() now return TestContainerBuilder rather than a container. Any existing test that type-hints the previous return, passes it directly to a assert* call, or calls container methods on the result will fail at runtime or in static analysis. Because this is a changed return type rather than a new method, there is no side-by-side period.BaseSymfonyIntegrationTestCase methods plus the $public argument remain callable, so failures will surface as deprecation notices/CI noise rather than hard errors. Deprecation-to-removal timeline is not stated — at 0.3.0 (pre-1.0) removal could land in 0.4.0.expectServiceExists() → expectDefinitionsExists() is not a pure rename; "definition exists" and "service exists" are different assertions in Symfony DI (a definition may be private, lazy, or synthetic). Teams doing mechanical find-and-replace may silently weaken assertions.Key questions.
TestContainerBuilder proxy the full container API, or must callers now terminate the builder (e.g. ->build()) before asserting?TestContainerBuilder usable standalone, i.e. can we test container wiring without subclassing BaseSymfonyIntegrationTestCase?$public semantics now expressed only via makePublic(), and what is the default visibility of a built container?Stack fit. PHP-only, dev-dependency, Composer-installable — no runtime footprint and no impact on production services. It fits any PHP 8.x stack with Symfony DI. It does not fit our Laravel testing layer: Laravel's Illuminate\Foundation\Testing\TestCase and its container do not expose Symfony bundle/extension concepts. Classify this as evaluate/reference, not adopt, unless a Symfony-based service is confirmed.
Migration path. Because 0.3.0 changes return types (not just adds methods), treat it as a minor-with-breakage and pin accordingly. Recommended path, if we already consume 0.2.x:
0.2.x in composer.json and freeze the version before any branch picks up 0.3.0.createContainer() / createContainerFromFile() — a single grep across tests/ is sufficient given the narrow API surface.createContainer* return value ($builder = $this->createContainer(); $builder->makePublic(...)->expectDefinitionsExists(...)).expectServiceExists() → expectDefinitionsExists(); do not trust automated renames here.^0.3.If we are not yet a consumer, do not adopt below 1.0; wait for the builder API to stabilise or vendor the pattern internally.
Compatibility. Pre-1.0 semver means "minor" releases may break — 0.3.0 confirms this. No stated minimum PHP/Symfony version in the notes; verify composer.json constraints for both symfony/dependency-injection and symfony/framework-bundle before planning. Coexistence with an existing PHPUnit/Pest matrix must be re-verified, since the base test case's construction path changed.
Sequencing. (a) Confirm whether we actually have a Symfony surface — this gates everything. (b) If no: archive as a pattern reference, extract the builder vocabulary into an internal Laravel test-support helper, no dependency taken. (c) If yes: pin, inventory, migrate, then upgrade on a single branch with full CI run before merge. (d) Request/author an English changelog as an exit criterion for adoption.
Maintenance. Low absolute surface area (one base test case plus one new builder class), but high churn velocity pre-1.0. Each release requires a re-read of a changelog that currently arrives in Russian, which effectively adds translation to the maintenance loop. Budget a recurring per-upgrade review, not a one-time integration.
Support. No vendor support; upstream issue tracker only. Failure diagnosis sits with whichever engineer owns the test harness. The deprecation notices give a usable migration map, which is the main mitigant — the mapping table in 0.3.0 is explicit and actionable.
Scaling. Dev-only, so it does not affect production throughput. Test-suite scale is the relevant axis: a builder that centralises container setup should reduce per-test boilerplate and improve suite runtime if it avoids repeated container rebuilds. Confirm that TestContainerBuilder is not rebuilding the kernel per assertion, which would regress large suites.
Failure modes.
TypeError/fatal in tests — loud, therefore safe, but it will block a CI pipeline on a routine dependency bump.expectServiceExists() → expectDefinitionsExists() is the highest-risk item; a mechanical rename may leave tests green while checking less than before.0.x release without warning, stranding pinned consumers.$public → makePublic() and locator semantics.Ramp-up. Low technical ramp-up (small API, familiar Symfony DI concepts), but non-trivial governance ramp-up: engineers must learn to (1) check the changelog in Russian, (2) treat every 0.x bump as potentially breaking, and (3) distinguish definition-level from service-level assertions. One half-day of onboarding plus a written internal migration note covers it. If adopting as a pattern reference only, ramp-up is effectively zero and the internalised vocabulary (makePublic, makeLocatable, expectDefinitionsExists) is the only durable output.
How can I help you explore Laravel packages today?