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

Plugin Phpunit Laravel Package

psalm/plugin-phpunit

A Psalm plugin for PHPUnit that improves static analysis of test suites by teaching Psalm about PHPUnit-specific APIs, assertions, and mocking. Install with Composer, enable via psalm-plugin, and get more accurate type checking in your tests. Requires Psalm v4 or later.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Release reviewed: 0.21.1 (published 2026-03-19) — supersedes the assessment baseline 0.20.0.

Verdict: Maintenance-only release. No breaking changes, no new analyzer features, no deprecations affecting consumers.

  • Rewrite README (PR #161): Documentation-only. Improves the "why/what" framing for the plugin — directly reduces developer ramp-up cost, our single largest adoption friction per the prior assessment.
  • Dependabot bumps (PRs #159, #162, #163): actions/cache 5→6, actions/checkout 6→7, symfony/yaml 6.4.18→6.4.48 inside /tools/behat. All confined to the plugin's own CI/Behat harness. Zero consumer-facing impact.
  • Annotate test fixtures instead of suppressing purity issues (PR #166): Internal hygiene — the plugin now annotates its own fixtures rather than using baseline suppressions. Not a behavior change for downstream projects, but a positive signal that the maintainers are reducing suppression debt rather than accumulating it.

Architecture Fit

  • Seamless Integration with Laravel/Psalm Ecosystem: Designed as a Psalm plugin, it leverages Psalm's static analysis engine to augment PHPUnit test validation. Aligns with Laravel's adoption of Psalm for type safety and PHPUnit for testing.
  • Attribute-First Design: Supports PHPUnit 9+ attributes (#[Test], #[DataProvider], #[Before]), critical for modern Laravel testing (e.g., Laravel's #[Test] usage under phpunit:10).
  • Type Inference for Tests: Reduces false positives by teaching Psalm about PHPUnit assertions (assertSame(), assertInstanceOf()), improving accuracy for Laravel's Eloquent, API response, and service container tests.
  • Plugin-Based Isolation: Encapsulates PHPUnit-specific logic; no contamination of core Psalm or Laravel systems.
  • Stability Signal (new): Two consecutive patch releases with no analyzer-behavior changes indicates the plugin has entered a maintenance cadence — favorable for long-lived Laravel applications.

Integration Feasibility

  • Low Friction: Two commands post-install:
    composer require --dev psalm/plugin-phpunit
    vendor/bin/psalm-plugin enable psalm/plugin-phpunit
    
  • Config-Driven: Works with existing psalm.xml (add <dir>tests/</dir> to <file-list>). No Laravel-specific overrides needed.
  • Dependency Alignment:
    • Psalm v5+: Matches the version targeted by Laravel's own tooling.
    • PHPUnit 9+/10: Fully supported; attribute syntax covered.
  • Version Pin (updated): Constraint should move from ^0.20 to ^0.21. Since 0.x semver permits breaking changes on minor bumps, pin to ^0.21 (not ^0) and review the changelog on every minor.
  • CI/CD Ready: Zero runtime overhead; runs as a pre-test static check (e.g., GitHub Actions via ./vendor/bin/psalm).
  • Onboarding Cost Reduced: The rewritten README now explains purpose and value up front — previously our top question from engineers unfamiliar with Psalm plugins. Expect a shorter path from "installed" to "understood."

Technical Risk

Risk Area Assessment Mitigation
Psalm Version Lock Plugin requires Psalm v5+; legacy Laravel projects may lag. Unchanged by 0.21.1. Audit composer.json for Psalm version; upgrade if <v5. Enforce with --strict.
Minor-Version Drift (0.x semver) 0.20.x → 0.21.x is a minor bump, which can carry breaking changes under 0.x semantics. The 0.21.1 notes show none, but we did not review 0.21.0. Action: review the 0.21.0 changelog before bumping. Pin ^0.21 and gate upgrades behind CI.
False Positives/Negatives Complex Laravel patterns (dynamic data providers) may trigger edge cases. Unchanged. Run --no-cache in CI to surface issues early; use <exclude-files> for stragglers.
Attribute Support Gaps Laravel-specific attributes (e.g., CreatesApplication) may not be recognized. Unchanged. Extend via Psalm's plugin API if needed (low priority — most tests use standard PHPUnit attributes).
Performance Overhead Static analysis adds ~10–30% to test-suite initialization (Psalm baseline). Unchanged. Cache in CI (--cache-globals); run in parallel with PHPUnit.
Breaking Changes None in 0.21.1. Release is docs, CI bumps, and internal fixture annotations. Standard changelog review on each minor.

Key Questions

  1. Psalm Adoption Maturity: Is Psalm already in the project's CI pipeline? If not, what's the blocker (warning fatigue, legacy code)? Fix critical issues first.
  2. Test Suite Complexity: What share of tests use data providers, attributes, or complex assertions (assertDatabaseHas)? Higher complexity = greater plugin value.
  3. CI/CD Pipeline Impact: Will Psalm run before PHPUnit to fail fast? What is the acceptable failure threshold (e.g., "block builds on test-related errors only")?
  4. Developer Ramp-Up: How will the team interpret Psalm warnings in tests? Concrete examples:
    • ❌ Argument 1 of assertSame() must be of type int, string given (e.g., $user->id is string but asserted as int)
    • ❌ Data provider must return iterable, array returned (e.g., missing yield)
    • New: Has the team read the rewritten README? It is now the recommended first-stop onboarding artifact.
  5. Long-Term Maintenance: Who triages Psalm warnings in tests ("Psalm Champion")? Who owns the dependency bump cadence? With 0.x semver, assign explicit ownership of minor-version review.
  6. New — Release Cadence Expectation: Are we prepared for frequent patch releases that are CI/docs-only? Confirm the upgrade process is cheap enough to run without ceremony, otherwise we will pin and drift.

Integration Approach

Stack Fit

  • Laravel + Psalm + PHPUnit 10:
    • Psalm: Static analysis for production code and tests.
    • PHPUnit 10: Modern attribute syntax (#[Test]) fully supported.
    • Composer: Dev dependency, zero runtime impact.
  • Toolchain Synergy:
    • Pint: Laravel's PHP formatter — no conflict.
    • PHPStan: If used, Psalm's stricter type system may reduce overlap; no direct conflict.
    • GitHub Actions: Add as a pre-test step:
      - name: Psalm (Tests)
        run: ./vendor/bin/psalm --init --no-cache --output-format=github
      

Migration Path

Phase Action Tools/Commands
Assessment Audit Psalm/PHPUnit versions and test complexity. composer show psalm/plugin-phpunit · grep -r "#[Test]" tests/
Installation Add plugin to composer.json and enable it. composer require --dev psalm/plugin-phpunit:^0.21 · vendor/bin/psalm-plugin enable psalm/plugin-phpunit
Configuration Update psalm.xml to include test files and configure strictness. <file-list><dir>app/</dir><dir>tests/</dir></file-list> + plugin-class registration
Validation Run Psalm on a subset of tests (e.g., tests/Unit/) to validate warnings. ./vendor/bin/psalm --init --no-cache
CI Integration Add Psalm to CI before PHPUnit. Psalm's published GitHub Actions template
Iteration Fix critical warnings (assertion type mismatches) and refine psalm.xml exclusions. Adjust <exclude-files> as needed
Upgrade Hygiene (new) On every 0.x minor bump, read the changelog; patches (e.g., 0.21.1) can be auto-merged if CI is green. Dependabot/Renovate with grouped patch updates

Compatibility

  • Laravel-Specific Considerations:
    • Eloquent Tests: Improved type checks for assertDatabaseHas(), assertModelExists().
    • API Testing: Validates assertJson()/assertJsonStructure() against actual response types.
    • Service Container: Catches mismatches in bind()/singleton() assertions.
  • Edge Cases:
    • Dynamic Data Providers: May require @psalm-suppress for complex generators (yield from).
    • Legacy PHPUnit 8: Unsupported; migrate to PHPUnit 10 for full attribute support.
    • Custom Assertions: Extend via Psalm's plugin API if needed.
  • 0.21.1 Compatibility Note: No API surface, config schema, or psalm.xml changes. Upgrade is a drop-in replacement for 0.20.x.

Sequencing

  1. Start with Unit Tests: Focus on tests/Unit/ first — lower complexity, higher ROI. Example: catch assertSame($user->id, 1) where $user->id is string.
  2. Expand to Feature Tests: Target assertion-heavy files (API JSON assertions, Eloquent existence checks) where type mismatches are most likely.
  3. Baseline and Gate: Freeze existing warnings in a Psalm baseline, fail builds only on new issues introduced by PRs.
  4. Harden CI: Add caching, then parallelize Psalm and PHPUnit.
  5. Establish Upgrade Rhythm: Patch releases (0.21.1) auto-merge on green CI; minor releases (0.21.0) get a changelog review by the named owner.

Operational Impact

Maintenance

  • Low steady-state burden. 0.21.1 is entirely docs, CI action bumps, and internal fixture annotation — no consumer action required beyond refreshing the version constraint.
  • Ownership: Name a Psalm Champion responsible for (a) triaging test-analysis warnings, (b) reviewing 0.x minor changelogs, and (c) maintaining the baseline file.
  • Dependency cadence: Patch releases can ride automated dependency updates; minor releases need a human read. Budget ~1 hour per minor release.

Support

  • Reduced support load (improved): The rewritten README directly addresses the historical "what does this plugin actually do?" question — the most common first-line support request from engineers new to the plugin. Expect fewer internal escalations during rollout.
  • Failure interpretation remains the support hotspot: Static-analysis errors in test files are unfamiliar to PHP developers who have only used PHPUnit. Pair the README with 2–3 internal worked examples of common warnings.
  • Vendor risk: Actively maintained, responsive to dependency hygiene, and willing to remove suppression debt (PR #166). Healthy project.

Scaling

  • Horizontal scaling of analysis is straightforward: Psalm is per-file, deterministic, and cache-friendly. Use --cache-globals and shard by directory (tests/Unit, tests/Feature) as the suite grows.
  • Cost grows with test count, not runtime: budget ~10–30% added wall-clock to the analysis stage; parallelize or cache to keep PR feedback under target latency.
  • Exclusion creep is the main scaling risk: over-excluding large feature tests to hit performance targets silently erodes value. Track exclude-files size as a hygiene metric.

Failure Modes

Failure Symptom Response
CI latency creep Pre-test analysis stage exceeds PR feedback budget Enable caching; shard by directory; parallelize with PHPUnit
Warning fatigue Team starts blanket-suppressing or excluding tests Enforce baseline-gated "new issues only"; review suppressions in code review
Silent vendor drift 0.x minor bump introduces behavior change unseen Pin ^0.21; require changelog review on minors; auto-merge patches only
False positives on dynamic providers Builds fail on valid Laravel test patterns Targeted @psalm-suppress with a comment; escalate upstream if recurring
Champion leaves Warnings accumulate, baseline grows, gate disabled Document the process in the repo; keep the workflow in CI config, not tribal knowledge

Ramp-Up

  • Estimated effort: 0.5–1 day for initial install, config, and CI wiring; 2–5 days of warning triage depending on existing type discipline; 1–2 sprints before the team reads warnings fluently.
  • Onboarding path (improved by 0.21.1): (1) Read the rewritten README; (2) run Psalm on tests/Unit/; (3) walk through 2–3 real warnings with the team; (4) enable the baseline-gated CI check.
  • No re-training required for this release — 0.21.1 introduces no new concepts, configuration, or workflows.
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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json