phpstan/phpstan-phpunit

PHPUnit extensions and rules for PHPStan

PHP

546

365 commits

updated Oct 13, 2026

See the code

README

PHPStan PHPUnit extensions and rules

Build Latest Stable Version License

This extension provides following features:

  • createMock(), getMockForAbstractClass() and getMockFromWsdl() methods return an intersection type (see the detailed explanation of intersection types) of the mock object and the mocked class so that both methods from the mock object (like expects) and from the mocked class are available on the object.
  • getMock() called on MockBuilder is also supported.
  • Interprets Foo|MockObject in phpDoc so that it results in an intersection type instead of a union type.
  • Defines early terminating method calls for the PHPUnit\Framework\TestCase class to prevent undefined variable errors.
  • Specifies types of expressions passed to various assert methods like assertInstanceOf, assertTrue, assertInternalType etc.
  • Combined with PHPStan's level 4, it points out always-true and always-false asserts like assertTrue(true) etc.

It also contains this strict framework-specific rules (can be enabled separately):

  • Check that you are not using assertSame() with true as expected value. assertTrue() should be used instead.
  • Check that you are not using assertSame() with false as expected value. assertFalse() should be used instead.
  • Check that you are not using assertSame() with null as expected value. assertNull() should be used instead.
  • Check that you are not using assertSame() with count($variable) as second parameter. assertCount($variable) should be used instead.
  • Check that you are not using assertEquals() with same types (assertSame() should be used)
  • Check that you are not using assertNotEquals() with same types (assertNotSame() should be used)
  • If PHPStan Strict Rules are enabled, PHPUnit's assertEmpty() and assertNotEmpty() assertions are disallowed as well.

How to document mock objects in phpDocs?

If you need to configure the mock even after you assign it to a property or return it from a method, you should add \PHPUnit\Framework\MockObject\MockObject to the type:

private function createFooMock(): Foo&\PHPUnit\Framework\MockObject\MockObject
{
	return $this->createMock(Foo::class);
}

public function testSomething(): void
{
	$fooMock = $this->createFooMock();
	$fooMock->method('doFoo')->will($this->returnValue('test'));
	$fooMock->doFoo();
}

If you cannot use native intersection types yet, you can use PHPDoc instead.

/**
 * @return Foo&\PHPUnit\Framework\MockObject\MockObject
 */
private function createFooMock(): Foo
{
	return $this->createMock(Foo::class);
}

Please note that the correct syntax for intersection types is Foo&\PHPUnit\Framework\MockObject\MockObject. Foo|\PHPUnit\Framework\MockObject\MockObject is also supported, but only for ecosystem and legacy reasons.

If the mock is fully configured and only the methods of the mocked class are supposed to be called on the value, it's fine to typehint only the mocked class:

private Foo $foo;

protected function setUp(): void
{
	$fooMock = $this->createMock(Foo::class);
	$fooMock->method('doFoo')->will($this->returnValue('test'));
	$this->foo = $fooMock;
}

public function testSomething(): void
{
	$this->foo->doFoo();
	// $this->foo->method() and expects() can no longer be called
}

Installation

To use this extension, require it in Composer:

composer require --dev phpstan/phpstan-phpunit

If you also install phpstan/extension-installer then you're all set!

Manual installation

If you don't want to use phpstan/extension-installer, include extension.neon in your project's PHPStan config:

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

To perform framework-specific checks, include also this file:

    - vendor/phpstan/phpstan-phpunit/rules.neon
php
php7
phpstan
phpunit
static-analysis
static-code-analysis
testing

phpstan/phpstan-phpunit

PHPUnit extensions and rules for PHPStan

PHP

546

365 commits

updated Oct 13, 2026

See the code

README

PHPStan PHPUnit extensions and rules

Build Latest Stable Version License

This extension provides following features:

  • createMock(), getMockForAbstractClass() and getMockFromWsdl() methods return an intersection type (see the detailed explanation of intersection types) of the mock object and the mocked class so that both methods from the mock object (like expects) and from the mocked class are available on the object.
  • getMock() called on MockBuilder is also supported.
  • Interprets Foo|MockObject in phpDoc so that it results in an intersection type instead of a union type.
  • Defines early terminating method calls for the PHPUnit\Framework\TestCase class to prevent undefined variable errors.
  • Specifies types of expressions passed to various assert methods like assertInstanceOf, assertTrue, assertInternalType etc.
  • Combined with PHPStan's level 4, it points out always-true and always-false asserts like assertTrue(true) etc.

It also contains this strict framework-specific rules (can be enabled separately):

  • Check that you are not using assertSame() with true as expected value. assertTrue() should be used instead.
  • Check that you are not using assertSame() with false as expected value. assertFalse() should be used instead.
  • Check that you are not using assertSame() with null as expected value. assertNull() should be used instead.
  • Check that you are not using assertSame() with count($variable) as second parameter. assertCount($variable) should be used instead.
  • Check that you are not using assertEquals() with same types (assertSame() should be used)
  • Check that you are not using assertNotEquals() with same types (assertNotSame() should be used)
  • If PHPStan Strict Rules are enabled, PHPUnit's assertEmpty() and assertNotEmpty() assertions are disallowed as well.

How to document mock objects in phpDocs?

If you need to configure the mock even after you assign it to a property or return it from a method, you should add \PHPUnit\Framework\MockObject\MockObject to the type:

private function createFooMock(): Foo&\PHPUnit\Framework\MockObject\MockObject
{
	return $this->createMock(Foo::class);
}

public function testSomething(): void
{
	$fooMock = $this->createFooMock();
	$fooMock->method('doFoo')->will($this->returnValue('test'));
	$fooMock->doFoo();
}

If you cannot use native intersection types yet, you can use PHPDoc instead.

/**
 * @return Foo&\PHPUnit\Framework\MockObject\MockObject
 */
private function createFooMock(): Foo
{
	return $this->createMock(Foo::class);
}

Please note that the correct syntax for intersection types is Foo&\PHPUnit\Framework\MockObject\MockObject. Foo|\PHPUnit\Framework\MockObject\MockObject is also supported, but only for ecosystem and legacy reasons.

If the mock is fully configured and only the methods of the mocked class are supposed to be called on the value, it's fine to typehint only the mocked class:

private Foo $foo;

protected function setUp(): void
{
	$fooMock = $this->createMock(Foo::class);
	$fooMock->method('doFoo')->will($this->returnValue('test'));
	$this->foo = $fooMock;
}

public function testSomething(): void
{
	$this->foo->doFoo();
	// $this->foo->method() and expects() can no longer be called
}

Installation

To use this extension, require it in Composer:

composer require --dev phpstan/phpstan-phpunit

If you also install phpstan/extension-installer then you're all set!

Manual installation

If you don't want to use phpstan/extension-installer, include extension.neon in your project's PHPStan config:

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

To perform framework-specific checks, include also this file:

    - vendor/phpstan/phpstan-phpunit/rules.neon
php
php7
phpstan
phpunit
static-analysis
static-code-analysis
testing

Project health

Overall

6.7/10

Maintained

10/10

Code review

5/10
OpenSSF Scorecard

Significant stargazers

Oskar Stark

327 followers · starred Nov 2019

Claudio Zizza

58 followers · starred Aug 2018

Gocha Ossinkine

8 followers · starred Jan 2018

Arne Jørgensen

62 followers · starred Jun 2021