From 68cf72c8870fc9a9ea07a1e0e11ce7cd9d69ff61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= Date: Sun, 14 Dec 2025 00:48:04 +0100 Subject: [PATCH] Enhance execution time reporting in PHPUnit - Added a new extension for execution timing in `phpunit.xml.dist`. - Updated `ExecutionTimeReportPrinter` to include formatted display of execution times in milliseconds and seconds. - Refactored test output assertions to check for new time formatting. - Introduced a helper method to extract specific lines from output for cleaner test code. --- phpunit.xml.dist | 9 ++++ .../ExecutionTimeReportPrinter.php | 42 ++++++++++++++--- tests/Unit/ExecutionTimeReportPrinterTest.php | 46 +++++++++---------- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d874aac..a9a044d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -17,6 +17,15 @@ + + + + + + + + + src diff --git a/src/ExecutionTimingExtension/ExecutionTimeReportPrinter.php b/src/ExecutionTimingExtension/ExecutionTimeReportPrinter.php index 5802fee..c2479e0 100644 --- a/src/ExecutionTimingExtension/ExecutionTimeReportPrinter.php +++ b/src/ExecutionTimingExtension/ExecutionTimeReportPrinter.php @@ -87,7 +87,7 @@ private function printTestLines(array $topTests): void /** * @param array $topTests - * @return array{rank: int, name: int} + * @return array{rank: int, name: int, timeMs: int, timeSec: int} */ private function calculateColumnWidths(array $topTests): array { @@ -100,15 +100,31 @@ private function calculateColumnWidths(array $topTests): array ) ); + $maxTimeMsWidth = max( + array_map( + static fn(array $test): int => strlen(sprintf('%.2f ms', round($test['time'] * 1000, 2))), + $topTests + ) + ); + + $maxTimeSecWidth = max( + array_map( + static fn(array $test): int => strlen(sprintf('(%.3f s)', round($test['time'], 3))), + $topTests + ) + ); + return [ 'rank' => $maxRankWidth, 'name' => $maxNameWidth, + 'timeMs' => $maxTimeMsWidth, + 'timeSec' => $maxTimeSecWidth, ]; } /** * @param array{name: string, time: float} $test - * @param array{rank: int, name: int} $columnWidths + * @param array{rank: int, name: int, timeMs: int, timeSec: int} $columnWidths */ private function printTestLine(array $test, int $rank, array $columnWidths): void { @@ -116,19 +132,21 @@ private function printTestLine(array $test, int $rank, array $columnWidths): voi $timeSec = round($test['time'], 3); $rankFormatted = $this->formatRank($rank, $columnWidths['rank']); $nameFormatted = $this->formatTestName($test['name'], $columnWidths['name']); + $timeMsFormatted = $this->formatTimeMs($timeMs, $columnWidths['timeMs']); + $timeSecFormatted = $this->formatTimeSec($timeSec, $columnWidths['timeSec']); $color = $this->determineColor($test['time']); $nameDisplay = $color !== '' ? Color::colorize($color, $nameFormatted) : $nameFormatted; - $timeMsDisplay = $color !== '' ? Color::colorize($color, sprintf('%.2f ms', $timeMs)) : sprintf('%.2f ms', $timeMs); - $timeSecDisplay = $color !== '' ? Color::colorize($color, sprintf('(%.3f s)', $timeSec)) : sprintf('(%.3f s)', $timeSec); + $timeMsDisplay = $color !== '' ? Color::colorize($color, $timeMsFormatted) : $timeMsFormatted; + $timeSecDisplay = $color !== '' ? Color::colorize($color, $timeSecFormatted) : $timeSecFormatted; printf( - " %s. %s : %s %s" . PHP_EOL, + " %s. ⏱ %s %s %s" . PHP_EOL, $rankFormatted, - $nameDisplay, $timeMsDisplay, - $timeSecDisplay + $timeSecDisplay, + $nameDisplay ); } @@ -159,4 +177,14 @@ private function formatTestName(string $name, int $width): string { return str_pad($name, $width, ' '); } + + private function formatTimeMs(float $timeMs, int $width): string + { + return str_pad(sprintf('%.2f ms', $timeMs), $width, ' ', STR_PAD_LEFT); + } + + private function formatTimeSec(float $timeSec, int $width): string + { + return str_pad(sprintf('(%.3f s)', $timeSec), $width, ' ', STR_PAD_LEFT); + } } diff --git a/tests/Unit/ExecutionTimeReportPrinterTest.php b/tests/Unit/ExecutionTimeReportPrinterTest.php index a69ecdb..1be4ecc 100644 --- a/tests/Unit/ExecutionTimeReportPrinterTest.php +++ b/tests/Unit/ExecutionTimeReportPrinterTest.php @@ -126,12 +126,12 @@ public function testPrintAlignsColumns(): void $firstLine = $testLines[0]; $secondLine = $testLines[1]; - $firstColonPos = strpos($firstLine, ':'); - $secondColonPos = strpos($secondLine, ':'); + $firstClockPos = strpos($firstLine, '⏱'); + $secondClockPos = strpos($secondLine, '⏱'); - $this->assertNotFalse($firstColonPos); - $this->assertNotFalse($secondColonPos); - $this->assertEquals($firstColonPos, $secondColonPos, 'Columns should be aligned'); + $this->assertNotFalse($firstClockPos); + $this->assertNotFalse($secondClockPos); + $this->assertEquals($firstClockPos, $secondClockPos, 'Columns should be aligned'); } } @@ -220,22 +220,16 @@ public function testPrintColorsCorrectlyWithMultipleThresholds(): void $output = ob_get_clean() ?: ''; // FastTest should not be colored - $fastTestPos = strpos($output, 'FastTest'); - $this->assertNotFalse($fastTestPos); - $fastTestLine = substr($output, $fastTestPos, 100); + $fastTestLine = $this->extractLineContaining($output, 'FastTest'); $this->assertStringNotContainsString("\x1b[", $fastTestLine); // WarningTest should be yellow - $warningTestPos = strpos($output, 'WarningTest'); - $this->assertNotFalse($warningTestPos); - $warningTestLine = substr($output, $warningTestPos, 200); + $warningTestLine = $this->extractLineContaining($output, 'WarningTest'); $this->assertStringContainsString("\x1b[33m", $warningTestLine); $this->assertStringNotContainsString("\x1b[31m", $warningTestLine); // DangerTest should be red - $dangerTestPos = strpos($output, 'DangerTest'); - $this->assertNotFalse($dangerTestPos); - $dangerTestLine = substr($output, $dangerTestPos, 200); + $dangerTestLine = $this->extractLineContaining($output, 'DangerTest'); $this->assertStringContainsString("\x1b[31m", $dangerTestLine); } @@ -254,21 +248,27 @@ public function testPrintRespectsThresholdConfiguration(): void $output = ob_get_clean() ?: ''; // Test1 (0.8s) should not be colored - $test1Pos = strpos($output, 'Test1'); - $this->assertNotFalse($test1Pos); - $test1Line = substr($output, $test1Pos, 100); + $test1Line = $this->extractLineContaining($output, 'Test1'); $this->assertStringNotContainsString("\x1b[", $test1Line); // Test2 (1.2s) should be yellow (>= 1.0 but < 2.0) - $test2Pos = strpos($output, 'Test2'); - $this->assertNotFalse($test2Pos); - $test2Line = substr($output, $test2Pos, 200); + $test2Line = $this->extractLineContaining($output, 'Test2'); $this->assertStringContainsString("\x1b[33m", $test2Line); // Test3 (3.0s) should be red (>= 2.0) - $test3Pos = strpos($output, 'Test3'); - $this->assertNotFalse($test3Pos); - $test3Line = substr($output, $test3Pos, 200); + $test3Line = $this->extractLineContaining($output, 'Test3'); $this->assertStringContainsString("\x1b[31m", $test3Line); } + + private function extractLineContaining(string $output, string $search): string + { + $lines = explode("\n", $output); + foreach ($lines as $line) { + if (str_contains($line, $search)) { + return $line; + } + } + + return ''; + } }