From 0c175772e55fc1be864f3e005c6d8e61e3ab7d26 Mon Sep 17 00:00:00 2001 From: butschster Date: Sun, 11 Jan 2026 16:32:12 +0400 Subject: [PATCH 1/3] feat: introduce TestCaseFactory for flexible test cases instantiation to give developers full control over test case instantiation. This enables dependency injection, custom initialization logic, and integration with existing DI containers. Features: - ReflectionFactory: Simple reflection-based instantiation (default) - ContainerFactory: PSR-11 container integration for DI support - CallableFactory: Custom factory logic via user-defined closures --- src/Application.php | 25 +++--- .../InstantiateTestCase.php | 7 +- .../Interceptor/InterceptorProvider.php | 2 +- src/Test/Factory/CallableFactory.php | 79 +++++++++++++++++++ src/Test/Factory/ContainerFactory.php | 60 ++++++++++++++ src/Test/Factory/ReflectionFactory.php | 54 +++++++++++++ src/Test/TestCaseFactory.php | 38 +++++++++ 7 files changed, 250 insertions(+), 15 deletions(-) create mode 100644 src/Test/Factory/CallableFactory.php create mode 100644 src/Test/Factory/ContainerFactory.php create mode 100644 src/Test/Factory/ReflectionFactory.php create mode 100644 src/Test/TestCaseFactory.php diff --git a/src/Application.php b/src/Application.php index 7a34b08..7ba4fcb 100644 --- a/src/Application.php +++ b/src/Application.php @@ -15,41 +15,40 @@ use Testo\Test\Dto\Status; use Testo\Test\Runner\SuiteRunner; use Testo\Test\SuiteProvider; +use Testo\Test\TestCaseFactory; +use Testo\Test\Factory; final class Application { private function __construct( private readonly ObjectContainer $container, + ?TestCaseFactory $testCaseFactory = null, ) { $config = $container->get(ApplicationConfig::class); $this->container->set($config); $this->applyPlugins($config->plugins); + + $this->container->set( + service: $testCaseFactory ?? new Factory\ReflectionFactory(), + id: TestCaseFactory::class, + ); } - /** - * Create the application instance with the provided configuration. - */ public static function createFromConfig( ApplicationConfig $config, + ?TestCaseFactory $testCaseFactory = null, ): self { $container = new ObjectContainer(); $container->set($config); - return new self($container); + return new self($container, $testCaseFactory); } - /** - * Create the application instance from ENV, CLI arguments, and config file. - * - * @param Path|null $configFile Path to config file - * @param array $inputOptions Command-line options - * @param array $inputArguments Command-line arguments - * @param array $environment Environment variables - */ public static function createFromInput( ?Path $configFile = null, array $inputOptions = [], array $inputArguments = [], array $environment = [], + ?TestCaseFactory $testCaseFactory = null, ): self { $container = new ObjectContainer(); $args = [ @@ -77,7 +76,7 @@ public static function createFromInput( $container->addInflector($container->make(ConfigInflector::class, $args)); $container->bind(Filter::class, Filter::fromScope(...)); - return new self($container); + return new self($container, $testCaseFactory); } public function run(?Filter $filter = null): RunResult diff --git a/src/Interceptor/TestCaseCallInterceptor/InstantiateTestCase.php b/src/Interceptor/TestCaseCallInterceptor/InstantiateTestCase.php index 32a2889..2b2514a 100644 --- a/src/Interceptor/TestCaseCallInterceptor/InstantiateTestCase.php +++ b/src/Interceptor/TestCaseCallInterceptor/InstantiateTestCase.php @@ -8,19 +8,24 @@ use Testo\Interceptor\TestCaseRunInterceptor; use Testo\Test\Dto\CaseInfo; use Testo\Test\Dto\CaseResult; +use Testo\Test\TestCaseFactory; /** * Instantiate the test case class if not already instantiated. */ final class InstantiateTestCase implements TestCaseRunInterceptor { + public function __construct( + private readonly TestCaseFactory $factory, + ) {} + #[\Override] public function runTestCase(CaseInfo $info, callable $next): CaseResult { if ($info->instance === null && $info->definition->reflection !== null) { try { # TODO don't instantiate if the test method is static - $instance = $info->definition->reflection->newInstance(); + $instance = $this->factory->create($info->definition->reflection); } catch (\Throwable $e) { throw new TestCaseInstantiationException(previous: $e); } diff --git a/src/Module/Interceptor/InterceptorProvider.php b/src/Module/Interceptor/InterceptorProvider.php index 71a9ae5..e6c28f2 100644 --- a/src/Module/Interceptor/InterceptorProvider.php +++ b/src/Module/Interceptor/InterceptorProvider.php @@ -56,7 +56,7 @@ public function fromConfig(string $class): array FilterInterceptor::class, new FilePostfixTestLocatorInterceptor(), new TestoAttributesLocatorInterceptor(), - new InstantiateTestCase(), + InstantiateTestCase::class, new AssertCollectorInterceptor(), TestInlineFinder::class, AttributesInterceptor::class, diff --git a/src/Test/Factory/CallableFactory.php b/src/Test/Factory/CallableFactory.php new file mode 100644 index 0000000..f49ad69 --- /dev/null +++ b/src/Test/Factory/CallableFactory.php @@ -0,0 +1,79 @@ + $class->newInstanceArgs($args) + * ); + * ``` + * + * Example - Conditional mock injection: + * ```php + * $factory = new CallableFactory( + * function(\ReflectionClass $class, array $args) { + * if ($class->implementsInterface(RequiresDatabaseInterface::class)) { + * return new $class->name($mockDatabase, ...$args); + * } + * return $class->newInstanceArgs($args); + * } + * ); + * ``` + * + * Example - Object pooling: + * ```php + * $pool = []; + * $factory = new CallableFactory( + * function(\ReflectionClass $class, array $args) use (&$pool) { + * $key = $class->getName(); + * return $pool[$key] ??= $class->newInstanceArgs($args); + * } + * ); + * ``` + * + * Example - Integration with custom factory: + * ```php + * $customFactory = new TestCaseFactory(); + * $factory = new CallableFactory( + * fn(\ReflectionClass $class) => $customFactory->create($class->getName()) + * ); + * ``` + * + * @template T of object + * @implements TestCaseFactory + */ +final class CallableFactory implements TestCaseFactory +{ + /** + * @param \Closure(\ReflectionClass, array): T $callable + */ + public function __construct( + private readonly \Closure $callable, + ) {} + + #[\Override] + public function create(\ReflectionClass $class, array $args = []): object + { + return ($this->callable)($class, $args); + } +} diff --git a/src/Test/Factory/ContainerFactory.php b/src/Test/Factory/ContainerFactory.php new file mode 100644 index 0000000..f6c54f0 --- /dev/null +++ b/src/Test/Factory/ContainerFactory.php @@ -0,0 +1,60 @@ +set(DatabaseConnection::class, $db); + * $container->set(UserRepository::class, fn() => new UserRepository($db)); + * + * $factory = new ContainerFactory($container); + * + * // Test class constructor receives injected dependencies + * class UserTest { + * public function __construct( + * private UserRepository $users, + * private DatabaseConnection $db + * ) {} + * } + * + * $test = $factory->create(new \ReflectionClass(UserTest::class)); + * // UserTest is created with injected UserRepository and DatabaseConnection + * ``` + * + * @template T of object + * @implements TestCaseFactory + */ +final class ContainerFactory implements TestCaseFactory +{ + /** + * @param ContainerInterface $container PSR-11 container for resolving dependencies + */ + public function __construct( + private readonly ContainerInterface $container, + ) {} + + /** + * @param \ReflectionClass $class + * @param array $args + * + * @return T + * + * @throws \Psr\Container\NotFoundExceptionInterface If the class is not found in the container + * @throws \Psr\Container\ContainerExceptionInterface If the container encounters an error during instantiation + */ + #[\Override] + public function create(\ReflectionClass $class, array $args = []): object + { + return $this->container->get($class->getName()); + } +} diff --git a/src/Test/Factory/ReflectionFactory.php b/src/Test/Factory/ReflectionFactory.php new file mode 100644 index 0000000..0d0cca4 --- /dev/null +++ b/src/Test/Factory/ReflectionFactory.php @@ -0,0 +1,54 @@ +create(new \ReflectionClass(SimpleTest::class)); + * + * // Class with constructor parameters + * $test = $factory->create( + * new \ReflectionClass(ParameterizedTest::class), + * ['param1', 42] + * ); + * ``` + * + * @template T of object + * @implements TestCaseFactory + */ +final class ReflectionFactory implements TestCaseFactory +{ + /** + * Creates an instance using reflection's newInstance method. + * + * @param \ReflectionClass $class Reflection of the class to instantiate + * @param array $args Constructor arguments in the order expected by the constructor + * + * @return T New instance of the class + * + * @throws \ReflectionException If the class cannot be instantiated: + * - Class is abstract or an interface + * - Constructor is not accessible + * - Required constructor parameters are missing + * - Constructor throws an exception + */ + #[\Override] + public function create(\ReflectionClass $class, array $args = []): object + { + if ($class->hasMethod('__construct') && $class->getMethod('__construct')->isPublic()) { + return $class->newInstance($args); + } + + return $class->newInstanceWithoutConstructor(); + } +} diff --git a/src/Test/TestCaseFactory.php b/src/Test/TestCaseFactory.php new file mode 100644 index 0000000..3b3ac7f --- /dev/null +++ b/src/Test/TestCaseFactory.php @@ -0,0 +1,38 @@ +create(new \ReflectionClass(MyTest::class)); + * ``` + * + * @template T of object + */ +interface TestCaseFactory +{ + /** + * Creates an instance of the specified test case class. + * + * @param \ReflectionClass $class Reflection of the class to create + * @param array $args Optional constructor arguments (implementation-specific) + * + * @return T Instance of the requested class + */ + public function create(\ReflectionClass $class, array $args = []): object; +} From e801dda94ee604a255b35a62077138c793152428 Mon Sep 17 00:00:00 2001 From: butschster Date: Sun, 11 Jan 2026 17:53:10 +0400 Subject: [PATCH 2/3] cover with tests --- src/Test/Definition/TestDefinition.php | 14 ++ src/Test/Factory/ReflectionFactory.php | 2 +- tests/Fixture/Factory/AbstractTestCase.php | 10 + tests/Fixture/Factory/Dependency.php | 12 + tests/Fixture/Factory/SimpleTestCase.php | 10 + .../Factory/TestCaseWithConstructor.php | 13 + .../Factory/TestCaseWithDependencies.php | 12 + .../TestCaseWithPrivateConstructor.php | 17 ++ tests/Testo/Factory/CallableFactoryTest.php | 25 ++ tests/Testo/Factory/ContainerFactoryTest.php | 150 ++++++++++++ tests/Testo/Factory/ReflectionFactoryTest.php | 63 +++++ .../Interceptor/InstantiateTestCaseTest.php | 231 ++++++++++++++++++ 12 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 tests/Fixture/Factory/AbstractTestCase.php create mode 100644 tests/Fixture/Factory/Dependency.php create mode 100644 tests/Fixture/Factory/SimpleTestCase.php create mode 100644 tests/Fixture/Factory/TestCaseWithConstructor.php create mode 100644 tests/Fixture/Factory/TestCaseWithDependencies.php create mode 100644 tests/Fixture/Factory/TestCaseWithPrivateConstructor.php create mode 100644 tests/Testo/Factory/CallableFactoryTest.php create mode 100644 tests/Testo/Factory/ContainerFactoryTest.php create mode 100644 tests/Testo/Factory/ReflectionFactoryTest.php create mode 100644 tests/Testo/Interceptor/InstantiateTestCaseTest.php diff --git a/src/Test/Definition/TestDefinition.php b/src/Test/Definition/TestDefinition.php index 8904e51..487f965 100644 --- a/src/Test/Definition/TestDefinition.php +++ b/src/Test/Definition/TestDefinition.php @@ -4,9 +4,23 @@ namespace Testo\Test\Definition; +use Testo\Attribute\Test; + final class TestDefinition { public function __construct( public readonly \ReflectionFunctionAbstract $reflection, ) {} + + public function getDescription(): ?string + { + $attributes = $this->reflection->getAttributes(Test::class); + if (\count($attributes) === 0) { + return null; + } + + /** @var Test $testAttribute */ + $testAttribute = $attributes[0]->newInstance(); + return $testAttribute->description !== '' ? $testAttribute->description : null; + } } diff --git a/src/Test/Factory/ReflectionFactory.php b/src/Test/Factory/ReflectionFactory.php index 0d0cca4..da767e9 100644 --- a/src/Test/Factory/ReflectionFactory.php +++ b/src/Test/Factory/ReflectionFactory.php @@ -46,7 +46,7 @@ final class ReflectionFactory implements TestCaseFactory public function create(\ReflectionClass $class, array $args = []): object { if ($class->hasMethod('__construct') && $class->getMethod('__construct')->isPublic()) { - return $class->newInstance($args); + return $class->newInstanceArgs($args); } return $class->newInstanceWithoutConstructor(); diff --git a/tests/Fixture/Factory/AbstractTestCase.php b/tests/Fixture/Factory/AbstractTestCase.php new file mode 100644 index 0000000..9759797 --- /dev/null +++ b/tests/Fixture/Factory/AbstractTestCase.php @@ -0,0 +1,10 @@ + $class->newInstanceArgs($args); + $factory = new CallableFactory($callable); + + $reflection = new \ReflectionClass(SimpleTestCase::class); + $instance = $factory->create($reflection); + + Assert::object($instance)->instanceOf(SimpleTestCase::class); + } +} diff --git a/tests/Testo/Factory/ContainerFactoryTest.php b/tests/Testo/Factory/ContainerFactoryTest.php new file mode 100644 index 0000000..64ae053 --- /dev/null +++ b/tests/Testo/Factory/ContainerFactoryTest.php @@ -0,0 +1,150 @@ +instance; + } + throw new class extends \Exception implements NotFoundExceptionInterface {}; + } + + public function has(string $id): bool + { + return $id === SimpleTestCase::class; + } + }; + + $factory = new ContainerFactory($container); + $reflection = new \ReflectionClass(SimpleTestCase::class); + $result = $factory->create($reflection); + + Assert::same($instance, $result); + } + + #[Test(description: 'Creates instance with dependencies resolved from container.')] + public function itResolvesDependenciesFromContainer(): void + { + $dependency = new Dependency(); + $testCase = new TestCaseWithDependencies($dependency); + + $container = new class($dependency, $testCase) implements ContainerInterface { + public function __construct( + private readonly Dependency $dependency, + private readonly TestCaseWithDependencies $testCase, + ) {} + + public function get(string $id): object + { + return match ($id) { + Dependency::class => $this->dependency, + TestCaseWithDependencies::class => $this->testCase, + default => throw new class extends \Exception implements NotFoundExceptionInterface {}, + }; + } + + public function has(string $id): bool + { + return in_array($id, [Dependency::class, TestCaseWithDependencies::class], true); + } + }; + + $factory = new ContainerFactory($container); + $reflection = new \ReflectionClass(TestCaseWithDependencies::class); + $result = $factory->create($reflection); + + Assert::same($testCase, $result); + Assert::same($dependency, $result->dependency); + } + + #[Test(description: 'Throws not found exception when class not in container.')] + public function itThrowsNotFoundExceptionWhenClassNotInContainer(): void + { + $container = new class implements ContainerInterface { + public function get(string $id): object + { + throw new class extends \Exception implements NotFoundExceptionInterface {}; + } + + public function has(string $id): bool + { + return false; + } + }; + + $factory = new ContainerFactory($container); + $reflection = new \ReflectionClass(SimpleTestCase::class); + + Expect::exception(NotFoundExceptionInterface::class); + $factory->create($reflection); + } + + #[Test(description: 'Throws container exception when container encounters error.')] + public function itThrowsContainerExceptionWhenContainerEncountersError(): void + { + $container = new class implements ContainerInterface { + public function get(string $id): object + { + throw new class extends \Exception implements \Psr\Container\ContainerExceptionInterface {}; + } + + public function has(string $id): bool + { + return true; + } + }; + + $factory = new ContainerFactory($container); + $reflection = new \ReflectionClass(SimpleTestCase::class); + + Expect::exception(\Psr\Container\ContainerExceptionInterface::class); + $factory->create($reflection); + } + + #[Test(description: 'Ignores constructor arguments as container resolves dependencies.')] + public function itIgnoresConstructorArguments(): void + { + $instance = new SimpleTestCase(); + $container = new class($instance) implements ContainerInterface { + public function __construct(private readonly object $instance) {} + + public function get(string $id): object + { + return $this->instance; + } + + public function has(string $id): bool + { + return true; + } + }; + + $factory = new ContainerFactory($container); + $reflection = new \ReflectionClass(SimpleTestCase::class); + $result = $factory->create($reflection, ['ignored', 'args']); + + Assert::same($instance, $result); + } +} diff --git a/tests/Testo/Factory/ReflectionFactoryTest.php b/tests/Testo/Factory/ReflectionFactoryTest.php new file mode 100644 index 0000000..d97dc76 --- /dev/null +++ b/tests/Testo/Factory/ReflectionFactoryTest.php @@ -0,0 +1,63 @@ +factory = new ReflectionFactory(); + } + + #[Test(description: 'Creates instance of simple class without constructor.')] + public function itCreatesInstanceWithoutConstructor(): void + { + $reflection = new \ReflectionClass(SimpleTestCase::class); + $instance = $this->factory->create($reflection); + + Assert::object($instance)->instanceOf(SimpleTestCase::class); + Assert::same('created', $instance->status); + } + + #[Test(description: 'Creates instance with constructor arguments.')] + public function itCreatesInstanceWithConstructorArguments(): void + { + $reflection = new \ReflectionClass(TestCaseWithConstructor::class); + $instance = $this->factory->create($reflection, ['test', 42]); + + Assert::object($instance)->instanceOf(TestCaseWithConstructor::class); + Assert::same('test', $instance->name); + Assert::same(42, $instance->value); + } + + #[Test(description: 'Creates instance without calling constructor when constructor is private.')] + public function itCreatesInstanceWithoutCallingConstructorWhenConstructorIsPrivate(): void + { + $reflection = new \ReflectionClass(TestCaseWithPrivateConstructor::class); + $instance = $this->factory->create($reflection); + + Assert::object($instance)->instanceOf(TestCaseWithPrivateConstructor::class); + } + + #[Test(description: 'Throws exception when trying to instantiate abstract class.')] + public function itThrowsExceptionWhenInstantiatingAbstractClass(): void + { + $reflection = new \ReflectionClass(AbstractTestCase::class); + + Expect::exception(\Error::class); + $this->factory->create($reflection); + } +} diff --git a/tests/Testo/Interceptor/InstantiateTestCaseTest.php b/tests/Testo/Interceptor/InstantiateTestCaseTest.php new file mode 100644 index 0000000..1d8d425 --- /dev/null +++ b/tests/Testo/Interceptor/InstantiateTestCaseTest.php @@ -0,0 +1,231 @@ +runTestCase($info, $next); + + Assert::true($nextCalled); + Assert::instanceOf(SimpleTestCase::class, $receivedInfo->instance); + Assert::same(Status::Passed, $result->status); + } + + #[Test(description: 'Skips instantiation when instance is already set.')] + public function itSkipsInstantiationWhenInstanceIsAlreadySet(): void + { + $interceptor = new InstantiateTestCase(new ReflectionFactory()); + $existingInstance = new SimpleTestCase(); + $definition = new CaseDefinition( + name: 'SimpleTestCase', + reflection: new \ReflectionClass(SimpleTestCase::class), + ); + $info = new CaseInfo($definition, instance: $existingInstance); + + $receivedInstance = null; + $next = function (CaseInfo $i) use (&$receivedInstance) { + $receivedInstance = $i->instance; + return new CaseResult( + results: [], + status: Status::Passed, + ); + }; + + $interceptor->runTestCase($info, $next); + + Assert::same($existingInstance, $receivedInstance); + } + + #[Test(description: 'Skips instantiation when reflection is null.')] + public function itSkipsInstantiationWhenReflectionIsNull(): void + { + $interceptor = new InstantiateTestCase(new ReflectionFactory()); + $definition = new CaseDefinition( + name: 'anonymous', + reflection: null, + ); + $info = new CaseInfo($definition, instance: null); + + $receivedInstance = null; + $next = function (CaseInfo $i) use (&$receivedInstance) { + $receivedInstance = $i->instance; + return new CaseResult( + results: [], + status: Status::Passed, + ); + }; + + $interceptor->runTestCase($info, $next); + + Assert::null($receivedInstance); + } + + #[Test(description: 'Wraps factory exceptions in TestCaseInstantiationException.')] + public function itWrapsFactoryExceptionInTestCaseInstantiationException(): void + { + $factory = new class implements TestCaseFactory { + public function create(\ReflectionClass $class, array $args = []): object + { + throw new \RuntimeException('Factory error'); + } + }; + + $interceptor = new InstantiateTestCase($factory); + $definition = new CaseDefinition( + name: 'SimpleTestCase', + reflection: new \ReflectionClass(SimpleTestCase::class), + ); + $info = new CaseInfo($definition, instance: null); + + $next = fn() => new CaseResult( + results: [], + status: Status::Passed, + ); + + Expect::exception(TestCaseInstantiationException::class); + + $interceptor->runTestCase($info, $next); + } + + #[Test(description: 'Preserves previous exception when wrapping in TestCaseInstantiationException.')] + public function itPreservesPreviousException(): void + { + $originalException = new \InvalidArgumentException('Invalid argument'); + + $factory = new class($originalException) implements TestCaseFactory { + public function __construct(private readonly \Throwable $exception) {} + + public function create(\ReflectionClass $class, array $args = []): object + { + throw $this->exception; + } + }; + + $interceptor = new InstantiateTestCase($factory); + $definition = new CaseDefinition( + name: 'SimpleTestCase', + reflection: new \ReflectionClass(SimpleTestCase::class), + ); + $info = new CaseInfo($definition, instance: null); + + $next = fn() => new CaseResult( + results: [], + status: Status::Passed, + ); + + $caught = false; + $previous = null; + + try { + $interceptor->runTestCase($info, $next); + } catch (TestCaseInstantiationException $e) { + $caught = true; + $previous = $e->getPrevious(); + } + + Assert::true($caught); + Assert::instanceOf(\InvalidArgumentException::class, $previous); + Assert::same('Invalid argument', $previous->getMessage()); + } + + #[Test(description: 'Throws exception when trying to instantiate abstract class.')] + public function itThrowsExceptionWhenInstantiatingAbstractClass(): void + { + $interceptor = new InstantiateTestCase(new ReflectionFactory()); + $definition = new CaseDefinition( + name: 'AbstractTestCase', + reflection: new \ReflectionClass(AbstractTestCase::class), + ); + $info = new CaseInfo($definition, instance: null); + + $next = fn() => new CaseResult( + results: [], + status: Status::Passed, + ); + + Expect::exception(TestCaseInstantiationException::class); + $interceptor->runTestCase($info, $next); + } + + #[Test(description: 'Instantiates class with private constructor using newInstanceWithoutConstructor.')] + public function itInstantiatesClassWithPrivateConstructorWithoutCallingConstructor(): void + { + $interceptor = new InstantiateTestCase(new ReflectionFactory()); + $definition = new CaseDefinition( + name: 'TestCaseWithPrivateConstructor', + reflection: new \ReflectionClass(TestCaseWithPrivateConstructor::class), + ); + $info = new CaseInfo($definition, instance: null); + + $next = function (CaseInfo $i) { + Assert::object($i->instance)->instanceOf(TestCaseWithPrivateConstructor::class); + return new CaseResult( + results: [], + status: Status::Passed, + ); + }; + + $interceptor->runTestCase($info, $next); + } + + #[Test(description: 'Creates new CaseInfo with instance via withInstance method.')] + public function itCreatesNewCaseInfoWithInstance(): void + { + $interceptor = new InstantiateTestCase(new ReflectionFactory()); + $definition = new CaseDefinition( + name: 'SimpleTestCase', + reflection: new \ReflectionClass(SimpleTestCase::class), + ); + $originalInfo = new CaseInfo($definition, instance: null); + + $next = function (CaseInfo $i) use ($originalInfo) { + Assert::notSame($originalInfo, $i, 'CaseInfo should be a new instance'); + Assert::object($i->instance)->instanceOf(SimpleTestCase::class); + return new CaseResult( + results: [], + status: Status::Passed, + ); + }; + + $interceptor->runTestCase($originalInfo, $next); + } +} From 495a95ffea08009ba1111f692b067e346af0f45e Mon Sep 17 00:00:00 2001 From: butschster Date: Sun, 11 Jan 2026 18:26:05 +0400 Subject: [PATCH 3/3] Remove unused method --- src/Test/Definition/TestDefinition.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/Test/Definition/TestDefinition.php b/src/Test/Definition/TestDefinition.php index 487f965..8904e51 100644 --- a/src/Test/Definition/TestDefinition.php +++ b/src/Test/Definition/TestDefinition.php @@ -4,23 +4,9 @@ namespace Testo\Test\Definition; -use Testo\Attribute\Test; - final class TestDefinition { public function __construct( public readonly \ReflectionFunctionAbstract $reflection, ) {} - - public function getDescription(): ?string - { - $attributes = $this->reflection->getAttributes(Test::class); - if (\count($attributes) === 0) { - return null; - } - - /** @var Test $testAttribute */ - $testAttribute = $attributes[0]->newInstance(); - return $testAttribute->description !== '' ? $testAttribute->description : null; - } }