codekandis / phpunit
`codekandis/phpunit` is a library for `PHPUnit` testing with enhanced test cases and custom constraint assertions.
Requires
- php: ^8.5
- phpunit/phpunit: ^13.1.10
Requires (Dev)
- phpstan/phpstan: ^2.1.54
- rector/rector: ^2.4.3
- roave/security-advisories: dev-master
README
codekandis/phpunit is a library for PHPUnit testing with enhanced test cases and
custom constraint assertions.
Index
- Installation
- Usage
Installation
Install the latest version with
$ composer require --dev codekandis/phpunit
Usage
Using the test case wrapper
Create a test case that extends the TestCase wrapper.
The additional constraint assertions are available through this wrapper.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; class ApplicationTest extends TestCase { }
Failing exception test branches
Use the protected fail helpers in test cases that assert exception control flow explicitly.
TestCase::failUnexpectedThrowableHasBeenThrown()
Use
TestCase::failUnexpectedThrowableHasBeenThrown() to fail
a test when a throwable has been thrown in a branch that must not throw.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; use Throwable; final class ServiceTest extends TestCase { public function testIfServiceRunsWithoutThrowable(): void { try { $service = new Service(); $service->run(); } catch ( Throwable $throwable ) { static::failUnexpectedThrowableHasBeenThrown( $throwable::class ); } static::assertTrue( $service->hasRun() ); } }
TestCase::failExpectedThrowableHasNotBeenThrown()
Use TestCase::failExpectedThrowableHasNotBeenThrown()
to fail a test when an expected throwable has not been thrown.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; use RuntimeException; final class ServiceTest extends TestCase { public function testIfServiceThrowsRuntimeException(): void { try { $service = new Service(); $service->fail(); } catch ( RuntimeException $throwable ) { static::assertSame( 'The service failed.', $throwable->getMessage() ); return; } static::failExpectedThrowableHasNotBeenThrown( RuntimeException::class ); } }
Using the data provider interface
Create a data provider that implements DataProviderInterface.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\DataProviderInterface; use Override; final class DifferentValuesDataProvider implements DataProviderInterface { #[Override] public static function provideData(): iterable { return [ 0 => [ 23, 42 ], 1 => [ 'foo', 'bar' ] ]; } }
Use the data provider in your test case through
DataProviderInterface::PROVIDER_METHOD_NAME.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; use CodeKandis\PhpUnit\DataProviderInterface; use PHPUnit\Framework\Attributes\DataProviderExternal; final class DifferentValuesTest extends TestCase { #[DataProviderExternal( DifferentValuesDataProvider::class, DataProviderInterface::PROVIDER_METHOD_NAME )] public function testValuesAreDifferent( mixed $value1, mixed $value2 ): void { static::assertNotSame( $value1, $value2 ); } }
Asserting array subsets
TestCase::assertArrayContainsKeyedSubset()
Use TestCase::assertArrayContainsKeyedSubset() to assert that
$actualArray contains $expectedSubset with matching keys and values. Set $strict to true to compare values
strictly, or to false to compare values loosely.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; final class ArrayTest extends TestCase { public function testArrayContainsKeyedSubset(): void { static::assertArrayContainsKeyedSubset( [ 'foo' => [ 'bar' => 23 ] ], [ 'foo' => [ 'bar' => 23, 'baz' => 42 ] ], true ); } }
TestCase::assertArrayContainsUnkeyedSubset()
Use TestCase::assertArrayContainsUnkeyedSubset() to assert
that $actualArray contains the values of $expectedSubset without comparing keys. Set $strict to true to compare
values strictly, or to false to compare values loosely.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; final class ArrayTest extends TestCase { public function testArrayContainsUnkeyedSubset(): void { static::assertArrayContainsUnkeyedSubset( [ 23, ], [ 42, 23 ], true ); } }
TestCase::assertIsKeyedSubsetOfArray()
Use TestCase::assertIsKeyedSubsetOfArray() to assert that
$actualSubset is contained in $expectedArray with matching keys and values. Set $strict to true to compare
values strictly, or to false to compare values loosely.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; final class ArrayTest extends TestCase { public function testKeyedSubsetIsSubsetOfArray(): void { static::assertIsKeyedSubsetOfArray( [ 'foo' => [ 'bar' => 23, 'baz' => 42 ] ], [ 'foo' => [ 'bar' => 23 ] ], true ); } }
TestCase::assertIsUnkeyedSubsetOfArray()
Use TestCase::assertIsUnkeyedSubsetOfArray() to assert that the
values of $actualSubset are contained in $expectedArray without comparing keys. Set $strict to true to compare
values strictly, or to false to compare values loosely.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; final class ArrayTest extends TestCase { public function testUnkeyedSubsetIsSubsetOfArray(): void { static::assertIsUnkeyedSubsetOfArray( [ 42, 23 ], [ 23 ], true ); } }
Asserting subclass relationships
TestCase::assertIsSubClassOf()
Use TestCase::assertIsSubClassOf() to assert that $actual is a subclass of
or implements $expectedInterfaceOrClassFqcn. $actual can be an object or an FQCN.
<?php declare( strict_types = 1 ); namespace Vendor\Project\Tests; use CodeKandis\PhpUnit\TestCase; interface MessageHandlerInterface { } final class MessageHandler implements MessageHandlerInterface { } final class MessageHandlerTest extends TestCase { public function testMessageHandlerImplementsMessageHandlerInterface(): void { static::assertIsSubClassOf( MessageHandlerInterface::class, MessageHandler::class ); } }
The assertion throws an
UnknownClassOrInterfaceException if the expected type does not
exist.