diff --git a/CHANGELOG.md b/CHANGELOG.md index ffff6884..1557685b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ For a full diff see [`7afa59c...main`][7afa59c...main]. * Added `Comparator\DurationComparator` ([#18]), by [@localheinz] * Added `SlowTestReporter` ([#19]), by [@localheinz] * Extracted `TimeKeeper` ([#22]), by [@localheinz] +* Extracted `Collector` ([#23]), by [@localheinz] ### Changed @@ -36,5 +37,6 @@ For a full diff see [`7afa59c...main`][7afa59c...main]. [#20]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/20 [#21]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/21 [#22]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/22 +[#23]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/23 [@localheinz]: https://github.com/localheinz diff --git a/src/Collector.php b/src/Collector.php new file mode 100644 index 00000000..69f16bf0 --- /dev/null +++ b/src/Collector.php @@ -0,0 +1,63 @@ + + */ + private array $slowTests = []; + + public function collect(SlowTest $slowTest): void + { + $key = self::key($slowTest->test()); + + if (\array_key_exists($key, $this->slowTests)) { + $previousSlowTest = $this->slowTests[$key]; + + if (!$slowTest->duration()->isGreaterThan($previousSlowTest->duration())) { + return; + } + + $this->slowTests[$key] = $slowTest; + + return; + } + + $this->slowTests[$key] = $slowTest; + } + + /** + * @phpstan-return list + * @psalm-return list + * + * @return array + */ + public function collected(): array + { + return \array_values($this->slowTests); + } + + private static function key(Event\Code\Test $test): string + { + return \sprintf( + '%s::%s', + $test->className(), + $test->methodNameWithDataSet(), + ); + } +} diff --git a/src/SlowTestCollector.php b/src/SlowTestCollector.php index d322e0bb..32c285c6 100644 --- a/src/SlowTestCollector.php +++ b/src/SlowTestCollector.php @@ -17,19 +17,20 @@ final class SlowTestCollector { - private TimeKeeper $timer; - private Event\Telemetry\Duration $maximumDuration; - /** - * @var array - */ - private array $slowTests = []; + private TimeKeeper $timer; - public function __construct(TimeKeeper $timeKeeper, Event\Telemetry\Duration $maximumDuration) - { - $this->timer = $timeKeeper; + private Collector $collector; + + public function __construct( + Event\Telemetry\Duration $maximumDuration, + TimeKeeper $timeKeeper, + Collector $collector + ) { $this->maximumDuration = $maximumDuration; + $this->timer = $timeKeeper; + $this->collector = $collector; } public function testPrepared(Event\Code\Test $test, Event\Telemetry\HRTime $preparedTime): void @@ -56,21 +57,7 @@ public function testPassed(Event\Code\Test $test, Event\Telemetry\HRTime $passed $duration ); - $key = self::key($test); - - if (\array_key_exists($key, $this->slowTests)) { - $previousSlowTest = $this->slowTests[$key]; - - if (!$duration->isGreaterThan($previousSlowTest->duration())) { - return; - } - - $this->slowTests[$key] = $slowTest; - - return; - } - - $this->slowTests[$key] = $slowTest; + $this->collector->collect($slowTest); } public function maximumDuration(): Event\Telemetry\Duration @@ -86,15 +73,6 @@ public function maximumDuration(): Event\Telemetry\Duration */ public function slowTests(): array { - return \array_values($this->slowTests); - } - - private static function key(Event\Code\Test $test): string - { - return \sprintf( - '%s::%s', - $test->className(), - $test->methodNameWithDataSet(), - ); + return $this->collector->collected(); } } diff --git a/test/Unit/CollectorTest.php b/test/Unit/CollectorTest.php new file mode 100644 index 00000000..8bcee465 --- /dev/null +++ b/test/Unit/CollectorTest.php @@ -0,0 +1,203 @@ +collected()); + } + + public function testCollectCollectsSlowTests(): void + { + $faker = self::faker(); + + $first = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'foo', + 'foo with data set #123', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $second = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'bar', + 'bar', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $third = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'baz', + 'baz with data set "string"', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $collector = new Collector(); + + $collector->collect($first); + $collector->collect($second); + $collector->collect($third); + + $expected = [ + $first, + $second, + $third, + ]; + + self::assertSame($expected, $collector->collected()); + } + + public function testCollectDoesNotReplaceSlowTestWhenDurationIsLessThanPreviousSlowTest(): void + { + $faker = self::faker(); + + $first = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'foo', + 'foo with data set #123', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(1), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $second = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'bar', + 'bar', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $thirdForSameTest = SlowTest::fromTestAndDuration( + new Event\Code\Test( + $first->test()->className(), + $first->test()->methodName(), + $first->test()->methodNameWithDataSet(), + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(0, $first->duration()->seconds() - 1), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $collector = new Collector(); + + $collector->collect($first); + $collector->collect($second); + $collector->collect($thirdForSameTest); + + $expected = [ + $first, + $second, + ]; + + self::assertSame($expected, $collector->collected()); + } + + public function testCollectReplacesSlowTestWhenDurationIsGreaterThanPreviousSlowTest(): void + { + $faker = self::faker(); + + $first = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'foo', + 'foo with data set #123', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $second = SlowTest::fromTestAndDuration( + new Event\Code\Test( + Fixture\ExampleTest::class, + 'bar', + 'bar', + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween(), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $thirdForSameTest = SlowTest::fromTestAndDuration( + new Event\Code\Test( + $first->test()->className(), + $first->test()->methodName(), + $first->test()->methodNameWithDataSet(), + ), + Event\Telemetry\Duration::fromSecondsAndNanoseconds( + $faker->numberBetween($first->duration()->seconds() + 1), + $faker->numberBetween(0, 999_999_999) + ) + ); + + $collector = new Collector(); + + $collector->collect($first); + $collector->collect($second); + $collector->collect($thirdForSameTest); + + $expected = [ + $thirdForSameTest, + $second, + ]; + + self::assertSame($expected, $collector->collected()); + } +} diff --git a/test/Unit/SlowTestCollectorTest.php b/test/Unit/SlowTestCollectorTest.php index b2950061..2f623cde 100644 --- a/test/Unit/SlowTestCollectorTest.php +++ b/test/Unit/SlowTestCollectorTest.php @@ -13,6 +13,7 @@ namespace Ergebnis\PHPUnit\SlowTestDetector\Test\Unit; +use Ergebnis\PHPUnit\SlowTestDetector\Collector; use Ergebnis\PHPUnit\SlowTestDetector\SlowTest; use Ergebnis\PHPUnit\SlowTestDetector\SlowTestCollector; use Ergebnis\PHPUnit\SlowTestDetector\TimeKeeper; @@ -25,6 +26,7 @@ * * @covers \Ergebnis\PHPUnit\SlowTestDetector\SlowTestCollector * + * @uses \Ergebnis\PHPUnit\SlowTestDetector\Collector * @uses \Ergebnis\PHPUnit\SlowTestDetector\SlowTest * @uses \Ergebnis\PHPUnit\SlowTestDetector\TimeKeeper */ @@ -37,8 +39,9 @@ public function testDefaults(): void $maximumDuration = Event\Telemetry\Duration::fromSeconds(self::faker()->numberBetween()); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); self::assertSame([], $slowTestCollector->slowTests()); @@ -49,8 +52,9 @@ public function testConstructorSetsValues(): void $maximumDuration = Event\Telemetry\Duration::fromSeconds(self::faker()->numberBetween()); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); self::assertSame($maximumDuration, $slowTestCollector->maximumDuration()); @@ -73,8 +77,9 @@ public function testDoesNotCollectSlowTestWhenTestHasBeenPreparedButHasNotPassed ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -102,8 +107,9 @@ public function testDoesNotCollectSlowTestWhenTestHasPassedButNotBeenPrepared(): ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPassed( @@ -138,8 +144,9 @@ public function testDoesNotCollectSlowTestWhenTestHasBeenPreparedAndPassedWithDu ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -179,8 +186,9 @@ public function testDoesNotCollectSlowTestWhenTestHasBeenPreparedAndPassedWithDu ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -220,8 +228,9 @@ public function testCollectsSlowTestWhenTestHasBeenPreparedAndPassedWithDuration ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -282,8 +291,9 @@ public function testDoesNotReplaceSlowTestWhenDurationIsGreaterThanMaximumDurati ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -347,8 +357,9 @@ public function testDoesNotReplaceSlowTestWhenDurationIsGreaterThanMaximumDurati ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -414,8 +425,9 @@ public function testReplacesSlowTestWhenDurationIsGreaterThanMaximumDurationAndG ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( @@ -528,8 +540,9 @@ public function testCollectsMultipleSlowTestsWhenDurationIsGreaterThanMaximumDur ); $slowTestCollector = new SlowTestCollector( + $maximumDuration, new TimeKeeper(), - $maximumDuration + new Collector() ); $slowTestCollector->testPrepared( diff --git a/test/Unit/Subscriber/TestPassedSubscriberTest.php b/test/Unit/Subscriber/TestPassedSubscriberTest.php index 8934561b..a92e0c65 100644 --- a/test/Unit/Subscriber/TestPassedSubscriberTest.php +++ b/test/Unit/Subscriber/TestPassedSubscriberTest.php @@ -13,6 +13,7 @@ namespace Ergebnis\PHPUnit\SlowTestDetector\Test\Unit\Subscriber; +use Ergebnis\PHPUnit\SlowTestDetector\Collector; use Ergebnis\PHPUnit\SlowTestDetector\SlowTest; use Ergebnis\PHPUnit\SlowTestDetector\SlowTestCollector; use Ergebnis\PHPUnit\SlowTestDetector\Subscriber\TestPassedSubscriber; @@ -26,6 +27,7 @@ * * @covers \Ergebnis\PHPUnit\SlowTestDetector\Subscriber\TestPassedSubscriber * + * @uses \Ergebnis\PHPUnit\SlowTestDetector\Collector * @uses \Ergebnis\PHPUnit\SlowTestDetector\SlowTest * @uses \Ergebnis\PHPUnit\SlowTestDetector\SlowTestCollector * @uses \Ergebnis\PHPUnit\SlowTestDetector\TimeKeeper @@ -38,8 +40,6 @@ public function testNotifyCollectsPreparedTest(): void { $faker = self::faker(); - $timeKeeper = new TimeKeeper(); - $maximumDuration = Event\Telemetry\Duration::fromSeconds($faker->numberBetween( 5, 10 @@ -65,8 +65,9 @@ public function testNotifyCollectsPreparedTest(): void ); $slowTestCollector = new SlowTestCollector( - $timeKeeper, - $maximumDuration + $maximumDuration, + new TimeKeeper(), + new Collector() ); $slowTestCollector->testPrepared( diff --git a/test/Unit/Subscriber/TestPreparedSubscriberTest.php b/test/Unit/Subscriber/TestPreparedSubscriberTest.php index 5fac7cb4..b0b4538c 100644 --- a/test/Unit/Subscriber/TestPreparedSubscriberTest.php +++ b/test/Unit/Subscriber/TestPreparedSubscriberTest.php @@ -13,6 +13,7 @@ namespace Ergebnis\PHPUnit\SlowTestDetector\Test\Unit\Subscriber; +use Ergebnis\PHPUnit\SlowTestDetector\Collector; use Ergebnis\PHPUnit\SlowTestDetector\SlowTest; use Ergebnis\PHPUnit\SlowTestDetector\SlowTestCollector; use Ergebnis\PHPUnit\SlowTestDetector\Subscriber\TestPreparedSubscriber; @@ -26,6 +27,7 @@ * * @covers \Ergebnis\PHPUnit\SlowTestDetector\Subscriber\TestPreparedSubscriber * + * @uses \Ergebnis\PHPUnit\SlowTestDetector\Collector * @uses \Ergebnis\PHPUnit\SlowTestDetector\SlowTest * @uses \Ergebnis\PHPUnit\SlowTestDetector\SlowTestCollector * @uses \Ergebnis\PHPUnit\SlowTestDetector\TimeKeeper @@ -38,8 +40,6 @@ public function testNotifyCollectsPreparedTest(): void { $faker = self::faker(); - $timeKeeper = new TimeKeeper(); - $maximumDuration = Event\Telemetry\Duration::fromSeconds($faker->numberBetween( 5, 10 @@ -65,8 +65,9 @@ public function testNotifyCollectsPreparedTest(): void $passedTest = clone $preparedTest; $slowTestCollector = new SlowTestCollector( - $timeKeeper, - $maximumDuration + $maximumDuration, + new TimeKeeper(), + new Collector() ); $subscriber = new TestPreparedSubscriber($slowTestCollector);