cdn77 / test-utils
Cdn77 Test Utils for PHP
Installs: 56 653
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 3
Forks: 2
Open Issues: 1
Requires
- php: ^8.2
- league/construct-finder: ^1.4
- phpunit/phpunit: ^10.1 || ^11
Requires (Dev)
README
Contents
Installation
- Require this project as composer dev dependency:
composer require --dev cdn77/test-utils
Features
Stub
Factory to create object through Reflection in order to bypass the constructor.
<?php class MyEntity { /** @var string */ private $property1; /** @var string */ private $property2; public function __construct(string $property1, string $property2) { $this->property1 = $property1; $this->property2 = $property2; } public function salute() : string { return sprintf('Hello %s!', $this->property2); } }
When testing method salute()
, you only need the tested class to have property2
set, you don't want to worry about property1
.
Therefore in your test you can initialize MyEntity
using Stub::create()
like this:
$myEntity = Stub::create(MyEntity::class, ['property2' => 'world']); self::assertSame('Hello world!', $myEntity->salute());
It comes handy when class constructor has more arguments and most of them are not required for your test.
It is possible to extend stubs:
$myEntity = Stub::create(MyEntity::class, ['property2' => 'world']); $myEntity = Stub::extends($myEntity, ['property1' => 'value']); // property 1 and 2 are set now self::assertSame('Hello world!', $myEntity->salute());
Test Checks
Test Checks are used to assert that tests comply with your suite's standards (are final, extend correct TestCaseBase etc.)
To run them, e.g. create a test case like in the following example:
<?php use Cdn77\TestUtils\TestCheck\TestCheck; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Group; #[CoversNothing] #[Group('integration')] final class SuiteComplianceTest extends TestCaseBase { /** @dataProvider providerChecks */ public function testChecks(TestCheck $check) : void { $check->run($this); } /** @return Generator<string, array{callable(self): TestCheck}> */ public static function providerChecks() : Generator { $testDir = ROOT_PROJECT_DIR . '/tests'; $testFilePathNames = \Symfony\Component\Finder\Finder::create() ->in($testDir) ->files() ->name('*Test.php'); yield 'Every test has group' => [ new EveryTestHasGroup($testFilePathNames), ]; ... } }
Every test has group
Asserts that all tests have a #[Group('x')]
attribute
❌
final class FooTest extends TestCase
✔️
use PHPUnit\Framework\Attributes\Group; #[Group('unit')] final class FooTest extends TestCase
Configured in test provider as
yield 'Every test has group' => [ new EveryTestHasGroup($testFiles), ];
Every test has same namespace as covered class
Asserts that all test share same namespace with class they're testing.
Consider src namespace Ns
and test namespace Ns/Tests
then for test Ns/Tests/UnitTest
must exist class Ns/Unit
.
You can use #[CoversClass]
attribute to link test with tested class.
Use #[CoversNothing]
attribute to skip this check.
Don't forget to enable requireCoverageMetadata="true"
in phpunit config file.
namespace Ns; final class Unit {}
❌
namespace Ns\Tests; final class NonexistentUnitTest extends TestCase {}
namespace Ns\Tests\Sub; final class UnitTest extends TestCase {}
✔️
namespace Ns\Tests; final class UnitTest extends TestCase {}
namespace Ns\Tests\Sub; use PHPUnit\Framework\Attributes\CoversClass; #[CoversClass('\Ns\Unit')] final class UnitTest extends TestCase {}
Configured in test provider as
yield 'Every test has same namespace as tested class' => [ new EveryTestHasSameNamespaceAsCoveredClass($testFiles), ];
Every test inherits from testcase base class
Consider you have a base for all tests and want each of them extend it.
abstract class TestCaseBase extends \PHPUnit\Framework\TestCase {}
❌
final class FooTest extends \PHPUnit\Framework\TestCase
✔️
final class FooTest extends TestCaseBase
Configured in test provider as
yield 'Every test inherits from TestCase Base Class' => [ new EveryTestInheritsFromTestCaseBaseClass( $testFiles, TestCaseBase::class ), ];
Every test is final
Asserts all tests are final so they cannot be extended
❌
class FooTest extends TestCase
✔️
final class FooTest extends TestCase
Configured in test provider as
yield 'Every test is final' => [ new EveryTestIsFinal($testFiles), ];