Weave Code
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

Phpstan Phpunit Laravel Package

phpstan/phpstan-phpunit

PHPStan extension for PHPUnit: improves type inference for mocks (intersection types for createMock/getMock), understands Foo|MockObject phpDocs, adds early-terminating methods to avoid undefined vars, and refines assert() types. Optional strict rules catch improper assertion usage.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by installing the package as a dev dependency:

composer require --dev phpstan/phpstan-phpunit

If you use phpstan/extension-installer, it autodiscoveres and loads the extension automatically. Otherwise, manually include it in your PHPStan config (phpstan.neon):

includes:
    - vendor/phpstan/phpstan-phpunit/extension.neon

For stricter PHPUnit-specific checks (e.g., enforcing assertTrue() over assertSame(true)), also include:

includes:
    - vendor/phpstan/phpstan-phpunit/rules.neon

The first real-world use case is running PHPStan on a test file that uses createMock()—you’ll immediately see correct type inference for mocks, including both the real class methods and mock-specific methods like expects() or method().

Implementation Patterns

  • Mock typing: Use native intersection types (Foo&\PHPUnit\Framework\MockObject\MockObject) or @return Foo&\PHPUnit\Framework\MockObject\MockObject in PHPDocs for methods returning mocks. This preserves access to both the mock API and the real class methods.

  • Late-stage mocking: After configuring a mock, reassign it to a property or variable typed only as Foo—PHPStan will now disallow further calls to expects()/method() (as expected), catching accidental misuse.

  • Type narrowing in assertions: assertInstanceOf(SomeClass::class, $var) narrows $var to SomeClass; assertTrue($isFoo) narrows to bool(true); assertNull($value) narrows to null. This works especially well at PHPStan level 4+, catching redundant/always-true assertions.

  • Auto-fixable rules: Enable AssertEqualsIsDiscouragedRule, AssertSameBooleanExpectedRule, and AssertSameNullExpectedRule to auto-fix violations (e.g., assertSame(true, $x)assertTrue($x)). Run PHPStan with --auto-fix.

  • DataProvider validation: With recent versions, DataProviderDataRule catches invalid or inconsistent data providers—e.g., mismatches between declared return types and actual values passed.

Gotchas and Tips

  • Intersection vs union type syntax matters: Foo|\PHPUnit\Framework\MockObject\MockObject is interpreted as a union (legacy behavior); only Foo&\PHPUnit\Framework\MockObject\MockObject gives the precise intersection. PHPStan warns if you use MockObject incorrectly as a standalone return type.

  • Mocking abstract classes: getMockForAbstractClass() returns a stub, not a strict mock—ensure you configure all abstract methods; PHPStan won’t complain about missing setups, but PHPUnit will at runtime.

  • assertArrayHasKey() limitations: In older PHPUnit versions, this rule may misbehave if keys are dynamic. Verify the key type is known (e.g., from array_keys() or array_column()).

  • Data providers must not use named args: PHPUnit 9/10 ignore named arguments in data providers; PHPStan’s phpstan-phpunit now flags this (phpunit.dataProviderStatic rule auto-fixes by turning arrays into static arrays).

  • @covers validation: Using @covers SomeInterface triggers a warning (interfaces can’t be covered). Always use concrete classes or fully qualified class names.

  • Auto-fix caution: Auto-fixes for assertEquals()assertSame() are safe only when types are known identical. Double-check changes, especially with loose comparisons (e.g., 0 == '0').

  • Extensibility: You can extend rule behavior by creating custom TypeSpecifyingExtension or MockObjectMethodCallRule classes and registering them manually in your PHPStan config.

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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport