Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Behat Code Coverage Laravel Package

dvdoug/behat-code-coverage

Behat Code Coverage is a Behat extension that generates PHP code coverage reports while running your test suite. It wraps php-code-coverage—the same library used by PHPUnit—so reports are familiar and interoperable with existing tooling.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What the package actually is. dvdoug/behat-code-coverage is a Behat extension — not a Laravel package. It registers a Behat service container extension that wraps phpunit/php-code-coverage around a Behat run, then emits reports in the formats developers already consume (Clover, Cobertura, OpenClover, HTML, text, serialized). It does not instrument anything itself; it is a thin, well-maintained adapter between Behat's lifecycle and the same coverage engine PHPUnit uses.

Architecture fit. Fit is entirely a function of whether the team runs Behat at all. Laravel's default and idiomatic test stack is PHPUnit/Pest, where coverage is native (php artisan test --coverage, --coverage-clover). If the team has no Behat suite, this package has zero value and should be rejected on the first pass. It becomes relevant only in the narrower case where Behat/Gherkin acceptance tests exist against a Laravel app (via laracasts/behat-laravel-extension or bespoke contexts) and stakeholders want a single coverage artifact spanning both unit and acceptance layers.

The critical technical risk: process locality. Coverage is collected in-process. Behat scenarios must exercise application code inside the same PHP process that started the Behat run. If the suite drives a separately booted php artisan serve/nginx/php-fpm instance over HTTP — the classic Laravel acceptance setup — instrumented coverage will be near-empty and misleading. The historical RemoteXDebug driver that addressed this was removed in 5.0.0. This is not a defect, but it forces an architectural decision (in-process kernel bootstrapping, e.g. Laravel's testing kernel invoked from a Behat context) before the package is worth adopting. Verify this before anything else.

Dependency coupling. The package's major-version cadence is pinned to phpunit/php-code-coverage majors (v14 supported per 5.4.2, v13 in 5.4.1, v12 in 5.3.7, v11 in 5.3.3, etc.). php-code-coverage is normally a transitive dev dependency of PHPUnit, so the practical failure mode is a Composer resolution conflict: the repo's PHPUnit pins one php-code-coverage major while the extension demands another. This is the single most likely integration blocker and is invisible until composer update runs. Symfony component support is 6 and 7 (Symfony 4 removed in 5.3.2); Laravel 8's Symfony 5.x floor therefore falls outside the supported matrix and would require an older, unsupported extension release.

Maturity and sustainability. Signals are mixed but net-positive on engineering hygiene and negative on adoption. Positives: conventional-commit changelog with explicit compatibility notes, GitHub Actions CI badge, Read the Docs site, BSD-2-Clause (permissive, low legal friction), and a demonstrated pattern of shipping upstream-compatibility releases quickly. Negatives: 62 stars, zero listed dependents, effectively a single-maintainer project, and a composite score of ~22. Bus factor is 1. For a dev-only tooling dependency that is acceptable; for anything load-bearing it is not. Treat it as a replaceable component with a documented exit (drop the extension, revert to PHPUnit-native coverage).

Key questions.

  1. Do we actually run Behat, and does it exercise the app in-process or over HTTP?
  2. Which phpunit/php-code-coverage major does our PHPUnit currently resolve, and does it intersect this package's constraint?
  3. Which Laravel/Symfony component versions are in play, and does the supported matrix cover them?
  4. What coverage driver is available (PCOV vs Xdebug) and is it enabled in CI images?
  5. Is there a hard coverage gate requirement, and if so, what enforces it (this package does not)?
  6. Who owns this dependency if the upstream maintainer stops?

Integration Approach

Stack fit. Composer-only, dev dependency, configured entirely through a behat.yml extension block (reports, filter, cache, branchAndPathCoverage). No application code changes, no service provider, no config publishing. That is an unusually clean integration surface: the blast radius is limited to the Behat profile file and composer.json. It sits comfortably alongside an existing PHPUnit coverage pipeline because both emit the same artifact types from the same engine — the outputs are directly comparable and mergeable in downstream tooling.

Migration path. Greenfield, not migration. Suggested sequence:

  1. Add as require-dev, run composer update --dry-run first to surface any php-code-coverage constraint conflict before touching the lockfile.
  2. Configure a single profile-scoped report (Clover) writing to a build artifact path, with filter scoped to app/ and explicit exclusions for vendor/, database/migrations/, and framework bootstrap files.
  3. Run locally under PCOV, confirm non-trivial line counts and that the file list matches the intended scope — a suspiciously empty or suspiciously complete report means the process-locality or filter problem, respectively.
  4. Wire into a dedicated CI job rather than appending to the existing unit-test job.

Compatibility and sequencing. Do the dependency resolution check as a timeboxed spike before any pipeline work; if it conflicts, fall back to running the extension in an isolated Composer profile or a separate CI job with its own lockfile rather than forcing a resolution in the main tree. Sequence the rollout behind the existing gates: land the Behat coverage job as non-blocking and reporting-only, let it accumulate a baseline for a sprint, then decide on thresholds. Do not introduce a gate in the same change that introduces the tool — you will not know whether a red build means a regression or a misconfiguration.

Tooling integration. Clover output is broadly consumable: SonarQube, Codecov, GitLab's coverage: regex, Jenkins, and most PR-bot coverage reporters accept it. Prefer Clover as the canonical format and add HTML only as a developer convenience artifact, since HTML reports are large and not diffable. Note that the package generates reports but does not enforce thresholds; if a gate is required, it must come from a downstream parser or the platform's native coverage policy.

Operational Impact

Maintenance. Low ongoing effort, bounded risk. The extension has no application-side code, so upgrades are Composer bumps plus a config review. The real maintenance cost is tracking the php-code-coverage/PHPUnit version treadmill: this package ships compatibility releases on the upstream major cadence, which means a PHPUnit major upgrade now has a second-order dependency to sequence. Budget a small but recurring allowance for that, and pin deliberately rather than floating.

Support and bus factor. Single maintainer, small user base, public issue tracker. Response quality is undocumented here; assume best-effort. Because the package is dev-only tooling, an abandonment scenario degrades gracefully — the fallback is deleting the extension and reverting to PHPUnit-native coverage, or forking (BSD-2-Clause permits it). This should be recorded as an explicit accepted risk rather than left implicit.

Scaling. Two cost axes. First, wall-clock: coverage instrumentation is expensive, and Behat suites are already the slowest layer; Xdebug-driven coverage can multiply runtime several-fold, which on a large Gherkin suite is the difference between a usable PR job and one that gets disabled. Mitigate with PCOV (substantially cheaper than Xdebug for line coverage, at the cost of branch/path coverage), scoping filter tightly, and enabling the static analysis cache key (defaults to the system temp dir — override to a CI-cacheable path to avoid re-parsing the codebase every run). Second, concurrency: the cache directory is shared state; parallelized Behat runs need per-worker cache paths or they will contend.

Failure modes and how they present.

  • No coverage driver (no PCOV, no Xdebug): the extension writes a warning to stderr since 5.3.5 and lets Behat complete. Non-blocking, but the artifact is missing — a lenient pipeline will silently ship no coverage. Treat a missing artifact as a failure at the pipeline level.
  • Xdebug loaded but coverage mode disabled: since 5.2.1 this is treated as "no driver" — warning, run continues. Same silent-gap risk.
  • Both PCOV and Xdebug loaded: improved handling landed in 5.3.1/5.3.2.1, but the guidance is still to load exactly one.
  • Empty or absurdly high coverage: almost always the process-locality issue or a filter that includes vendor — a configuration error masquerading as a quality signal, and the most damaging failure because it looks like data.
  • Composer constraint conflict: hard failure at install time, visible and cheap to catch early.
  • Report path collisions across parallel CI jobs: silent overwrite, last-writer-wins artifacts.
  • Relative-path handling: improved in 5.3.4, but running from a non-repo-root working directory is a known friction point; use absolute output paths.

Ramp-up. Genuinely small for anyone already fluent in Behat profiles and Composer: an afternoon to a first report, a day or two to a stable CI job. The hidden cost is not the package — it is the prerequisite fluency in Behat's extension/container model and in coverage-driver operations, plus the architectural work of making the acceptance suite run in-process. Teams without a Behat suite should not adopt this to acquire one. Teams with a Behat suite that drives a real web server should expect the majority of the effort to land on restructuring the test harness, not on the extension.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names