1. Go to this page and download the library: Download rybakit/phpunit-extras library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
rybakit / phpunit-extras example snippets
use App\Tests\Attribute\RequiresMySqlServer;
use App\Tests\Attribute\Sql;
use PHPUnitExtras\TestCase;
#[RequiresMySqlServer('^5.6|^8.0')]
final class CacheableRepositoryTest extends TestCase
{
#[Sql('DROP TABLE IF EXISTS %target_method%')]
#[Sql('CREATE TABLE %target_method% (id INT UNSIGNED PRIMARY KEY)')]
#[Sql('INSERT INTO %target_method% (id) VALUES (1)')]
public function testFindByIdCachesResultSet() : void
{
$tableName = $this->resolvePlaceholders('%target_method%');
$repository = $this->createRepository($tableName);
$this->expectSelectStatementToBeExecutedOnce();
$repository->findById(1);
$repository->findById(1);
}
}
use PHPUnitExtras\TestCase;
final class MyTest extends TestCase
{
// ...
}
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\Before;
use PHPUnitExtras\Attribute\Attributes;
final class MyTest extends TestCase
{
use Attributes;
#[Before]
protected function processTestAttributesBeforeTest() : void
{
$this->processTestAttributes(static::class, $this->name());
}
// ...
}
#[RequiresIf('<condition>')]
use PHPUnitExtras\Attribute\RequiresIf;
#[RequiresIf('server.AWS_ACCESS_KEY_ID')]
#[RequiresIf('server.AWS_SECRET_ACCESS_KEY')]
final class AwsS3AdapterTest extends TestCase
{
// ...
}
namespace App\Tests;
use PHPUnitExtras\Attribute\ProcessableAttribute;
use PHPUnitExtras\Attribute\PlaceholderResolver\PlaceholderResolver;
use PHPUnitExtras\Attribute\Requirement\Requirement;
use PHPUnitExtras\Attribute\Target;
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class RequiresFeature implements ProcessableAttribute
{
public function __construct(public readonly string $feature)
{
}
}
final class FeatureRequirement implements Requirement
{
public function getAttributeClass() : string
{
return RequiresFeature::class;
}
public function check(ProcessableAttribute $attribute, Target $target, PlaceholderResolver $placeholderResolver) : ?string
{
if (!$attribute instanceof RequiresFeature) {
throw new \InvalidArgumentException('FeatureRequirement only handles RequiresFeature attributes');
}
$feature = $placeholderResolver->resolve($attribute->feature, $target);
return FeatureFlags::isEnabled($feature)
? null
: \sprintf('Feature "%s" is
use PHPUnitExtras\Attribute\RequiresConstant;
#[RequiresConstant('Redis::SERIALIZER_MSGPACK')]
public function testSerializeToMessagePack() : void
{
// ...
}
use PHPUnitExtras\Attribute\RequiresPackage;
#[RequiresPackage('symfony/uid ^5.1')]
public function testUseUuidAsPrimaryKey() : void
{
// ...
}
namespace App\Tests;
#[Example('%target_class%')]
#[Example('%target_class_full%')]
final class FoobarTest extends TestCase
{
// ...
}
#[Example('%target_method%')]
#[Example('%target_method_full%')]
public function testFoobar() : void
{
// ...
}
#[Log('%tmp_dir%/%target_class%.%target_method%.log testing Foobar')]
public function testFoobar() : void
{
// ...
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Attribute\Processor\Processor;
use PHPUnitExtras\Attribute\ProcessableAttribute;
use PHPUnitExtras\Attribute\PlaceholderResolver\PlaceholderResolver;
use PHPUnitExtras\Attribute\Target;
final class SqlProcessor implements Processor
{
private $conn;
public function __construct(\PDO $conn)
{
$this->conn = $conn;
}
public function getAttributeClasses() : array
{
return [Sql::class];
}
public function process(ProcessableAttribute $attribute, Target $target, PlaceholderResolver $placeholderResolver) : void
{
\assert($attribute instanceof Sql);
$sql = $placeholderResolver->resolve($attribute->sql, $target);
$this->conn->exec($sql);
}
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Attribute\ProcessableAttribute;
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class Sql implements ProcessableAttribute
{
public function __construct(public readonly string $sql)
{
}
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Attribute\PlaceholderResolver\PlaceholderResolver;
use PHPUnitExtras\Attribute\Target;
final class TableNameResolver implements PlaceholderResolver
{
public function getName() : string
{
return 'table_name';
}
/**
* Replaces all occurrences of "%table_name%" with
* "table_<short-class-name>[_<short-method-name>]".
*/
public function resolve(string $value, Target $target) : string
{
$tableName = 'table_'.$target->getClassShortName();
if ($target->isOnMethod()) {
$tableName .= '_'.$target->getMethodShortName();
}
return strtr($value, ['%table_name%' => $tableName]);
}
}
namespace App\Tests;
use App\Tests\PhpUnit\SqlProcessor;
use App\Tests\PhpUnit\TableNameResolver;
use PHPUnitExtras\Attribute\AttributeProcessorBuilder;
use PHPUnitExtras\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
protected function createAttributeProcessorBuilder() : AttributeProcessorBuilder
{
return parent::createAttributeProcessorBuilder()
->addProcessor(new SqlProcessor($this->getConnection()))
->addPlaceholderResolver(new TableNameResolver());
}
protected function getConnection() : \PDO
{
// TODO: Implement getConnection() method.
}
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Attribute\AttributeExtension as BaseAttributeExtension;
use PHPUnitExtras\Attribute\AttributeProcessorBuilder;
use PHPUnit\Runner\Extension\Facade;
use PHPUnit\Runner\Extension\ParameterCollection;
use PHPUnit\TextUI\Configuration\Configuration;
class AttributeExtension extends BaseAttributeExtension
{
private string $dsn = 'mysql:host=localhost;dbname=test';
private ?\PDO $conn = null;
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters) : void
{
if ($parameters->has('dsn')) {
$this->dsn = $parameters->get('dsn');
}
parent::bootstrap($configuration, $facade, $parameters);
}
protected function createAttributeProcessorBuilder() : AttributeProcessorBuilder
{
return parent::createAttributeProcessorBuilder()
->addProcessor(new SqlProcessor($this->getConnection()))
->addPlaceholderResolver(new TableNameResolver());
}
protected function getConnection() : \PDO
{
return $this->conn ?? $this->conn = new \PDO($this->dsn);
}
}
namespace App\Tests\PhpUnit;
use PHPUnit\Framework\Assert;
use PHPUnitExtras\Expectation\Expectation;
final class FileCreatedExpectation implements Expectation
{
private $filename;
public function __construct(string $filename)
{
Assert::assertFileDoesNotExist($filename);
$this->filename = $filename;
}
public function verify() : void
{
Assert::assertFileExists($this->filename);
}
}
use PHPUnit\Framework\TestCase;
use PHPUnitExtras\Expectation\Expectations;
final class MyTest extends TestCase
{
use Expectations;
protected function tearDown() : void
{
$this->verifyExpectations();
}
// ...
}
public function testDumpPdfToFile() : void
{
$filename = sprintf('%s/foobar.pdf', sys_get_temp_dir());
$this->expect(new FileCreatedExpectation($filename));
$this->generator->dump($filename);
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Expectation\Expectation;
trait FileExpectations
{
public function expectFileToBeCreated(string $filename) : void
{
$this->expect(new FileCreatedExpectation($filename));
}
// ...
abstract protected function expect(Expectation $expectation) : void;
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Expectation\ExpressionContext;
final class SelectStatementCountContext implements ExpressionContext
{
private $conn;
private $expression;
private $initialValue;
private $finalValue;
private function __construct(\PDO $conn, string $expression)
{
$this->conn = $conn;
$this->expression = $expression;
$this->initialValue = $this->getValue();
}
public static function exactly(\PDO $conn, int $count) : self
{
return new self($conn, "new_count === old_count + $count");
}
public static function atLeast(\PDO $conn, int $count) : self
{
return new self($conn, "new_count >= old_count + $count");
}
public static function atMost(\PDO $conn, int $count) : self
{
return new self($conn, "new_count <= old_count + $count");
}
public function getExpression() : string
{
return $this->expression;
}
public function getValues() : array
{
if (null === $this->finalValue) {
$this->finalValue = $this->getValue();
}
return [
'old_count' => $this->initialValue,
'new_count' => $this->finalValue,
];
}
private function getValue() : int
{
$stmt = $this->conn->query("SHOW GLOBAL STATUS LIKE 'Com_select'");
$stmt->execute();
return (int) $stmt->fetchColumn(1);
}
}
namespace App\Tests\PhpUnit;
use PHPUnitExtras\Expectation\Expectation;
use PHPUnitExtras\Expectation\ExpressionExpectation;
trait SelectStatementExpectations
{
public function expectSelectStatementToBeExecuted(int $count) : void
{
$context = SelectStatementCountContext::exactly($this->getConnection(), $count);
$this->expect(new ExpressionExpectation($context));
}
public function expectSelectStatementToBeExecutedOnce() : void
{
$this->expectSelectStatementToBeExecuted(1);
}
// ...
abstract protected function expect(Expectation $expectation) : void;
abstract protected function getConnection() : \PDO;
}
use App\Tests\PhpUnit\SelectStatementExpectations;
use PHPUnitExtras\TestCase;
final class CacheableRepositoryTest extends TestCase
{
use SelectStatementExpectations;
public function testFindByIdCachesResultSet() : void
{
$repository = $this->createRepository();
$this->expectSelectStatementToBeExecutedOnce();
$repository->findById(1);
$repository->findById(1);
}
// ...
protected function getConnection() : \PDO
{
// TODO: Implement getConnection() method.
}
}