Skip to content

Commit

Permalink
Allow kernel configuration via attributes (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdreesen authored Mar 19, 2024
1 parent c35974e commit 8782d66
Show file tree
Hide file tree
Showing 12 changed files with 334 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v0.12.1
### Features:
- Allow kernel configuration via attributes

## v0.12.0
### Features:
- Dynamically configurable test kernel with which you can register bundles, load configurations,
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,34 @@ class SomeTest extends ConfigurableKernelTestCase
}
```
An alternative to passing a `config` closure in the `options` array to `ConfigurableKernelTestCase::bootKernel()`
is to use attributes for the kernel configuration.
```php
use Neusta\Pimcore\TestingFramework\Test\Attribute\ConfigureContainer;
use Neusta\Pimcore\TestingFramework\Test\Attribute\ConfigureExtension;
use Neusta\Pimcore\TestingFramework\Test\Attribute\RegisterBundle;
use Neusta\Pimcore\TestingFramework\Test\Attribute\RegisterCompilerPass;
use Neusta\Pimcore\TestingFramework\Test\ConfigurableKernelTestCase;
#[RegisterBundle(SomeBundle::class)]
class SomeTest extends ConfigurableKernelTestCase
{
#[ConfigureContainer(__DIR__ . '/Fixtures/some_config.yaml')]
#[ConfigureExtension('some_extension', ['config' => 'values'])]
#[RegisterCompilerPass(new SomeCompilerPass())]
public function test_something(): void
{
self::bootKernel();
// test something
}
}
```
> [!TIP]
> All attributes can be used on class *and* test method level.
### Integration Tests With a Database
If you write integration tests that use the database, we've got you covered too.
Expand Down
23 changes: 23 additions & 0 deletions src/Test/Attribute/ConfigureContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class ConfigureContainer implements KernelConfiguration
{
/**
* @param string $config path to a config file
*/
public function __construct(
private readonly string $config,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestConfig($this->config);
}
}
24 changes: 24 additions & 0 deletions src/Test/Attribute/ConfigureExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class ConfigureExtension implements KernelConfiguration
{
/**
* @param array<string, array<mixed>> $extensionConfig
*/
public function __construct(
private readonly string $namespace,
private readonly array $extensionConfig,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestExtensionConfig($this->namespace, $this->extensionConfig);
}
}
11 changes: 11 additions & 0 deletions src/Test/Attribute/KernelConfiguration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;

interface KernelConfiguration
{
public function configure(TestKernel $kernel): void;
}
24 changes: 24 additions & 0 deletions src/Test/Attribute/RegisterBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class RegisterBundle implements KernelConfiguration
{
/**
* @param class-string<BundleInterface> $bundle
*/
public function __construct(
private readonly string $bundle,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestBundle($this->bundle);
}
}
27 changes: 27 additions & 0 deletions src/Test/Attribute/RegisterCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Attribute;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;

#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
final class RegisterCompilerPass implements KernelConfiguration
{
/**
* @param PassConfig::TYPE_* $type
*/
public function __construct(
private readonly CompilerPassInterface $compilerPass,
private readonly string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION,
private readonly int $priority = 0,
) {
}

public function configure(TestKernel $kernel): void
{
$kernel->addTestCompilerPass($this->compilerPass, $this->type, $this->priority);
}
}
27 changes: 26 additions & 1 deletion src/Test/ConfigurableKernelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,45 @@
namespace Neusta\Pimcore\TestingFramework\Test;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Neusta\Pimcore\TestingFramework\Test\Attribute\KernelConfiguration;
use Neusta\Pimcore\TestingFramework\Test\Reflection\TestAttributeProvider;
use Pimcore\Test\KernelTestCase;

abstract class ConfigurableKernelTestCase extends KernelTestCase
{
/** @var list<KernelConfiguration> */
private static iterable $kernelConfigurations = [];

/**
* @param array<mixed> $options
* @param array{config?: callable(TestKernel):void, environment?: string, debug?: bool, ...} $options
*/
protected static function createKernel(array $options = []): TestKernel
{
$kernel = parent::createKernel($options);
\assert($kernel instanceof TestKernel);

foreach (self::$kernelConfigurations as $configuration) {
$configuration->configure($kernel);
}

$kernel->handleOptions($options);

return $kernel;
}

/**
* @internal
*
* @before
*/
public function _getKernelConfigurationFromAttributes(): void
{
self::$kernelConfigurations = (new TestAttributeProvider($this))->getKernelConfigurationAttributes();
}

protected function tearDown(): void
{
self::$kernelConfigurations = [];
parent::tearDown();
}
}
49 changes: 49 additions & 0 deletions src/Test/Reflection/TestAttributeProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);

namespace Neusta\Pimcore\TestingFramework\Test\Reflection;

use Neusta\Pimcore\TestingFramework\Test\Attribute\KernelConfiguration;
use PHPUnit\Framework\TestCase;

/**
* @internal
*/
final class TestAttributeProvider
{
private \ReflectionMethod $test;

public function __construct(TestCase $test)
{
$this->test = new \ReflectionMethod($test, $test->getName(false));
}

/**
* @return list<KernelConfiguration>
*/
public function getKernelConfigurationAttributes(): array
{
$attributes = [];
foreach ($this->getAttributes($this->test->getDeclaringClass(), KernelConfiguration::class) as $attribute) {
$attributes[] = $attribute->newInstance();
}

foreach ($this->getAttributes($this->test, KernelConfiguration::class) as $attribute) {
$attributes[] = $attribute->newInstance();
}

return $attributes;
}

/**
* @template T of object
*
* @param class-string<T> $attribute
*
* @return iterable<\ReflectionAttribute<T>>
*/
private function getAttributes(\ReflectionClass|\ReflectionMethod $source, string $attribute): iterable
{
yield from $source->getAttributes($attribute, \ReflectionAttribute::IS_INSTANCEOF);
}
}
35 changes: 33 additions & 2 deletions tests/Functional/CompilerPassTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace Neusta\Pimcore\TestingFramework\Tests\Functional;

use Neusta\Pimcore\TestingFramework\Kernel\TestKernel;
use Neusta\Pimcore\TestingFramework\Test\Attribute\RegisterCompilerPass;
use Neusta\Pimcore\TestingFramework\Test\ConfigurableKernelTestCase;
use Neusta\Pimcore\TestingFramework\Tests\Fixtures\ConfigurationBundle\DependencyInjection\Compiler\DeregisterSomethingPass;
use Neusta\Pimcore\TestingFramework\Tests\Fixtures\ConfigurationBundle\DependencyInjection\Compiler\RegisterSomethingPass;
Expand All @@ -22,15 +23,15 @@ public function compiler_pass_priority(): void
$kernel->addTestCompilerPass(new RegisterSomethingPass());
}]);

$this->assertTrue(self::getContainer()->has('something'));
self::assertTrue(self::getContainer()->has('something'));

// Case 2: Compiler pass with priority - it should be prioritized by priority
self::bootKernel(['config' => function (TestKernel $kernel) {
$kernel->addTestCompilerPass(new DeregisterSomethingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5);
$kernel->addTestCompilerPass(new RegisterSomethingPass());
}]);

$this->assertFalse(self::getContainer()->has('something'));
self::assertFalse(self::getContainer()->has('something'));

// Case 3: Compiler pass without priority - it should be prioritized by order of addition
self::bootKernel(['config' => function (TestKernel $kernel) {
Expand All @@ -39,6 +40,36 @@ public function compiler_pass_priority(): void
$kernel->addTestCompilerPass(new DeregisterSomethingPass());
}]);

self::assertFalse(self::getContainer()->has('something'));
}

/**
* @test
*/
#[RegisterCompilerPass(new DeregisterSomethingPass())]
#[RegisterCompilerPass(new RegisterSomethingPass())]
public function compiler_passes_via_attributes(): void
{
$this->assertTrue(self::getContainer()->has('something'));
}

/**
* @test
*/
#[RegisterCompilerPass(new DeregisterSomethingPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5)]
#[RegisterCompilerPass(new RegisterSomethingPass())]
public function compiler_passes_with_priority_via_attributes(): void
{
$this->assertFalse(self::getContainer()->has('something'));
}

/**
* @test
*/
#[RegisterCompilerPass(new RegisterSomethingPass())]
#[RegisterCompilerPass(new DeregisterSomethingPass())]
public function compiler_passes_without_priority_via_attributes(): void
{
$this->assertFalse(self::getContainer()->has('something'));
}
}
Loading

0 comments on commit 8782d66

Please sign in to comment.