diff --git a/README.md b/README.md index c8ed70c..022442f 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Add the extension to your `phpunit.xml.dist` or `phpunit.xml` file: + @@ -46,6 +47,7 @@ Add the extension to your `phpunit.xml.dist` or `phpunit.xml` file: - **`topN`** (default: `10`): Number of slowest tests to display in the summary report - **`showIndividualTimings`** (default: `false`): Whether to display timing for each test as it runs +- **`showFQCN`** (default: `true`): Whether to display fully qualified class names (FQCN) or just the class name. When set to `false`, only the class name without namespace will be shown (e.g., `MyTestClass::testMethod` instead of `Phauthentic\PHPUnit\ExecutionTiming\Tests\MyTestClass::testMethod`) - **`warningThreshold`** (default: `1.0`): Time in seconds at which tests will be colored yellow (warning). Tests with execution time >= this value will be highlighted. - **`dangerThreshold`** (default: `5.0`): Time in seconds at which tests will be colored red (danger). Tests with execution time >= this value will be highlighted in red. Tests between `warningThreshold` and `dangerThreshold` will be colored yellow. @@ -122,6 +124,22 @@ This configuration will: - Show yellow for tests taking 0.5 seconds or more - Show red for tests taking 2.0 seconds or more +### With Short Class Names (showFQCN disabled) + +```xml + + + + + + + + +``` + +This configuration will display only the class name without the full namespace path, making the output more compact: +- `MyTestClass::testMethod` instead of `Phauthentic\PHPUnit\ExecutionTiming\Tests\MyTestClass::testMethod` + ## How It Works The extension subscribes to PHPUnit events: diff --git a/src/ExecutionTimingExtension/ExecutionTimeExtension.php b/src/ExecutionTimingExtension/ExecutionTimeExtension.php index 2b98ad8..ece3395 100644 --- a/src/ExecutionTimingExtension/ExecutionTimeExtension.php +++ b/src/ExecutionTimingExtension/ExecutionTimeExtension.php @@ -30,6 +30,7 @@ final class ExecutionTimeExtension implements Extension private float $testStartTime = 0.0; private int $topN = 10; private bool $showIndividualTimings = false; + private bool $showFQCN = true; private float $warningThreshold = 1.0; private float $dangerThreshold = 5.0; @@ -51,14 +52,15 @@ public function onTestFinished(Finished $event): void { $duration = microtime(true) - $this->testStartTime; $testName = $event->test()->id(); + $displayName = $this->formatTestName($testName); $this->testTimes[] = [ - 'name' => $testName, + 'name' => $displayName, 'time' => $duration, ]; if ($this->showIndividualTimings) { $timeMs = round($duration * 1000, 2); - printf(" ⏱ %s: %.2f ms\n", $testName, $timeMs); + printf(" ⏱ %s: %.2f ms\n", $displayName, $timeMs); } } @@ -109,5 +111,34 @@ public function extractConfigurationFromParameters(ParameterCollection $paramete if ($parameters->has('dangerThreshold')) { $this->dangerThreshold = (float)$parameters->get('dangerThreshold'); } + + if ($parameters->has('showFQCN')) { + $this->showFQCN = filter_var( + $parameters->get('showFQCN'), + FILTER_VALIDATE_BOOLEAN + ); + } + } + + private function formatTestName(string $testName): string + { + if ($this->showFQCN) { + return $testName; + } + + // Extract class name from format: Fully\Qualified\ClassName::methodName + if (str_contains($testName, '::')) { + $parts = explode('::', $testName, 2); + $className = $parts[0]; + $methodName = $parts[1] ?? ''; + + // Get just the class name (last part of namespace) + $classNameParts = explode('\\', $className); + $shortClassName = end($classNameParts); + + return $shortClassName . ($methodName !== '' ? '::' . $methodName : ''); + } + + return $testName; } } diff --git a/tests/Unit/ExecutionTimeExtensionTest.php b/tests/Unit/ExecutionTimeExtensionTest.php index d8405c8..8ba7bd0 100644 --- a/tests/Unit/ExecutionTimeExtensionTest.php +++ b/tests/Unit/ExecutionTimeExtensionTest.php @@ -133,4 +133,139 @@ public function testOnExecutionFinishedWithNoTests(): void $this->assertEmpty($output); } + + public function testDefaultShowFQCNIsTrue(): void + { + $reflection = new \ReflectionClass($this->extension); + $property = $reflection->getProperty('showFQCN'); + $property->setAccessible(true); + + $this->assertTrue($property->getValue($this->extension)); + } + + public function testExtractConfigurationFromParametersWithShowFQCNTrue(): void + { + $parameters = ParameterCollection::fromArray([ + 'showFQCN' => 'true', + ]); + + $reflection = new \ReflectionClass($this->extension); + $method = $reflection->getMethod('extractConfigurationFromParameters'); + $method->setAccessible(true); + $method->invoke($this->extension, $parameters); + + $property = $reflection->getProperty('showFQCN'); + $property->setAccessible(true); + + $this->assertTrue($property->getValue($this->extension)); + } + + public function testExtractConfigurationFromParametersWithShowFQCNFalse(): void + { + $parameters = ParameterCollection::fromArray([ + 'showFQCN' => 'false', + ]); + + $reflection = new \ReflectionClass($this->extension); + $method = $reflection->getMethod('extractConfigurationFromParameters'); + $method->setAccessible(true); + $method->invoke($this->extension, $parameters); + + $property = $reflection->getProperty('showFQCN'); + $property->setAccessible(true); + + $this->assertFalse($property->getValue($this->extension)); + } + + public function testFormatTestNameWithFQCNEnabled(): void + { + $reflection = new \ReflectionClass($this->extension); + $method = $reflection->getMethod('formatTestName'); + $method->setAccessible(true); + + $testName = 'Phauthentic\\PHPUnit\\ExecutionTiming\\Tests\\Unit\\MyTestClass::testMethod'; + $result = $method->invoke($this->extension, $testName); + + $this->assertEquals('Phauthentic\\PHPUnit\\ExecutionTiming\\Tests\\Unit\\MyTestClass::testMethod', $result); + } + + public function testFormatTestNameWithFQCNDisabled(): void + { + $parameters = ParameterCollection::fromArray([ + 'showFQCN' => 'false', + ]); + + $reflection = new \ReflectionClass($this->extension); + $extractMethod = $reflection->getMethod('extractConfigurationFromParameters'); + $extractMethod->setAccessible(true); + $extractMethod->invoke($this->extension, $parameters); + + $formatMethod = $reflection->getMethod('formatTestName'); + $formatMethod->setAccessible(true); + + $testName = 'Phauthentic\\PHPUnit\\ExecutionTiming\\Tests\\Unit\\MyTestClass::testMethod'; + $result = $formatMethod->invoke($this->extension, $testName); + + $this->assertEquals('MyTestClass::testMethod', $result); + } + + public function testFormatTestNameWithFQCNDisabledAndNoNamespace(): void + { + $parameters = ParameterCollection::fromArray([ + 'showFQCN' => 'false', + ]); + + $reflection = new \ReflectionClass($this->extension); + $extractMethod = $reflection->getMethod('extractConfigurationFromParameters'); + $extractMethod->setAccessible(true); + $extractMethod->invoke($this->extension, $parameters); + + $formatMethod = $reflection->getMethod('formatTestName'); + $formatMethod->setAccessible(true); + + $testName = 'MyTestClass::testMethod'; + $result = $formatMethod->invoke($this->extension, $testName); + + $this->assertEquals('MyTestClass::testMethod', $result); + } + + public function testFormatTestNameWithFQCNDisabledAndNoMethodName(): void + { + $parameters = ParameterCollection::fromArray([ + 'showFQCN' => 'false', + ]); + + $reflection = new \ReflectionClass($this->extension); + $extractMethod = $reflection->getMethod('extractConfigurationFromParameters'); + $extractMethod->setAccessible(true); + $extractMethod->invoke($this->extension, $parameters); + + $formatMethod = $reflection->getMethod('formatTestName'); + $formatMethod->setAccessible(true); + + $testName = 'Phauthentic\\PHPUnit\\ExecutionTiming\\Tests\\Unit\\MyTestClass'; + $result = $formatMethod->invoke($this->extension, $testName); + + $this->assertEquals('Phauthentic\\PHPUnit\\ExecutionTiming\\Tests\\Unit\\MyTestClass', $result); + } + + public function testFormatTestNameWithFQCNDisabledAndSingleNamespaceLevel(): void + { + $parameters = ParameterCollection::fromArray([ + 'showFQCN' => 'false', + ]); + + $reflection = new \ReflectionClass($this->extension); + $extractMethod = $reflection->getMethod('extractConfigurationFromParameters'); + $extractMethod->setAccessible(true); + $extractMethod->invoke($this->extension, $parameters); + + $formatMethod = $reflection->getMethod('formatTestName'); + $formatMethod->setAccessible(true); + + $testName = 'MyNamespace\\MyTestClass::testMethod'; + $result = $formatMethod->invoke($this->extension, $testName); + + $this->assertEquals('MyTestClass::testMethod', $result); + } }