happyr/service-mocking
HappyR Service Mocking is a Laravel testing helper that makes it easy to replace real services with mocks in the container. Swap bindings during functional and integration tests to isolate dependencies and control behavior without manual container wiring or boilerplate.
Architecture fit. happyr/service-mocking is a Symfony bundle plus a ServiceMockTrait that swaps real service definitions inside a compiled DI container for PHPUnit/Mockery doubles, targeting KernelTestCase. Laravel has no compile step and no test container of its own; it binds at runtime through Illuminate\Container\Container and service providers. Laravel's native $this->mock(), $this->partialMock(), $this->spy(), and $this->instance() already cover the bulk of "mock a service inside the built container." As a literal dependency for a Laravel app, the architecture fit is poor; as a pattern reference for container-level mocking it is decent.
Integration feasibility. Low as a drop-in. The package requires symfony/dependency-injection, symfony/framework-bundle, and a Symfony kernel test base class. Those libraries coexist in a Laravel vendor tree (Laravel already ships Symfony components), but the bundle is not auto-registered by Laravel's provider system and the trait targets the wrong base test case. A wrapper that maps getMockedService() semantics onto app()->instance() / bind() is feasible in roughly one to three engineer-days — but at that point the team is reimplementing a small concept, not integrating a package. With 45 stars and zero dependents, there is no documented Laravel usage path; the team would be the first.
Technical risk. Medium, and confined to CI since this is a require-dev package. The dominant risk is version lock-step: Symfony 5–7 support must track Laravel's pinned Symfony components (Laravel 11 → Symfony 7, Laravel 10 → 6.4), and the two will not upgrade on the same cadence. Container manipulation also has sharp edges — private services, aliases, decorated services, final classes, readonly promoted properties — that Laravel-only engineers have no intuition for. Maintenance is single-vendor (a Swedish consultancy), though the 2024-10-08 release is a positive signal that it is not abandoned.
Key questions.
$this->mock() / $this->instance()? Is the pain "mock a service constructed deep inside a provider" or "mock at container-compile time"? Only the latter justifies anything resembling this package.Stack fit. Target is PHP 8.1+ / Laravel 10–11. The package's public API is a trait plus a bundle; neither has an Illuminate counterpart. For a Laravel-only codebase the practical fit is "inspiration, not dependency." Standardize instead on $this->mock(Contract::class, ...), $this->instance(), $this->spy(), and container bind() overrides in a shared test case. That covers roughly 90% of the described capability with zero new dependencies. If compile-time-style mocking is genuinely required, build a small internal MockableServiceRegistry that records intended bindings before bootstrap() and applies them in register()/boot() — the Laravel-idiomatic rendering of this package's idea.
Migration path. Do not introduce the Symfony bundle into the Laravel app. Port the concept: a MockableServices test trait that resolves configured service IDs from app(), rebinds them to Mockery doubles in setUp(), and restores originals via app()->forgetInstance() in tearDown(). If a genuine Symfony service exists in the estate (queue worker, CLI tool, extracted microservice), pilot the real package there first — composer require --dev happyr/service-mocking, register the bundle only in the test environment, and use ServiceMockTrait in KernelTestCase subclasses. Prove the pattern on the Symfony side, then decide whether Laravel parity is worth the port.
Compatibility. Pin the package's Symfony major support and verify against Laravel's transitive Symfony components explicitly; expect friction at every Symfony major bump. Mockery/PHPUnit alignment is the likelier break — validate the trait's mocking contract against the PHPUnit major in use. There is no facade, no package discovery, and nothing lands in config/.
Sequencing.
Maintenance. Adopting it in a Laravel app means owning an unsupported integration. The package is small (a compiler pass plus a trait), so vendoring or forking is cheap if the maintainer goes quiet — but that cost must be accepted up front. A dev-only dependency still appears in composer.lock, Dependabot noise, and security-scan reports. The internal-adapter alternative costs more initially and far less over its lifetime; total cost of ownership favors the adapter for a Laravel-native team.
Support. No Laravel community, no Stack Overflow corpus, no first-party documentation for Illuminate. The support channel is the Happyr GitHub issue tracker, prioritized by consulting needs rather than user demand. Ramp-up is trivial for Symfony engineers and non-trivial for Laravel-only engineers, for whom compiler passes and kernel bootstrapping are foreign concepts.
Scaling. Negligible runtime cost: dev-only, test-environment-only, no production footprint, no per-request overhead. The real constraint is test-suite scale. Per-test container swapping tends to be heavier than Laravel's per-test $this->instance(); at thousands of tests the lighter native path wins.
Failure modes.
new or a static factory rather than the container, the mock is never injected and the test passes against the real service. This is the most dangerous failure mode and the one most likely to erode trust in the tool.Ramp-up. Symfony-familiar engineer: productive in under a day. Laravel-only engineer: two to three days before the compiled-container model clicks, plus recurring friction at every upgrade. If the decision is "adopt the concept, not the package," write it up once so the team does not re-litigate it each quarter.
TPM recommendation. Do not add happyr/service-mocking to a Laravel application; it solves a Symfony problem Laravel has already solved. Adopt the pattern via a small internal trait, or use the package directly only where a genuine Symfony surface exists. The 0.535 score and 29.15 opportunity score match that read: a well-made, narrowly scoped tool that is poorly matched to this stack. Frame it as a tactical convenience worth a one-sprint spike only if that spike proves Laravel's built-in fakes cannot reach the services we care about.
How can I help you explore Laravel packages today?