diff --git a/.github/workflows/integrate.yaml b/.github/workflows/integrate.yaml
index db82574..190d8a5 100644
--- a/.github/workflows/integrate.yaml
+++ b/.github/workflows/integrate.yaml
@@ -15,36 +15,9 @@ jobs:
runs-on: "ubuntu-latest"
strategy:
- fail-fast: false
-
matrix:
- include:
- - php-version: "7.2"
- phpunit-version: "8.*"
-
- - php-version: "7.3"
- phpunit-version: "8.*"
-
- - php-version: "7.3"
- phpunit-version: "9.*"
-
- - php-version: "7.4"
- phpunit-version: "8.*"
-
- - php-version: "7.4"
- phpunit-version: "9.*"
-
- - php-version: "8.0"
- phpunit-version: "8.*"
-
- - php-version: "8.0"
- phpunit-version: "9.*"
-
- - php-version: "8.1"
- phpunit-version: "8.*"
-
- - php-version: "8.1"
- phpunit-version: "9.*"
+ php-version:
+ - "8.1"
steps:
- name: "Checkout"
@@ -69,8 +42,8 @@ jobs:
key: "php-${{ matrix.php-version }}-composer-${{ matrix.phpunit-version }}"
restore-keys: "php-${{ matrix.php-version }}-composer-"
- - name: "Require phpunit/phpunit ${{ matrix.phpunit-version }}"
- run: "composer require phpunit/phpunit:${{ matrix.phpunit-version }}"
+ - name: "Install dependencies with composer"
+ run: "composer install --no-interaction --no-progress"
- name: "Run tests with phpunit/phpunit"
run: "vendor/bin/phpunit"
diff --git a/README.md b/README.md
index df1c428..f2dafae 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ Enable with all defaults by adding the following code to your project's `phpunit
...
-
+
```
@@ -46,18 +46,10 @@ Each parameter is set in `phpunit.xml`:
-
-
-
-
- 500
-
-
- 10
-
-
-
-
+
+
+
+
```
@@ -132,7 +124,7 @@ Step 1) Enable SpeedTrap in phpunit.xml. The slowness report will output during
...
-
+
```
@@ -165,7 +157,7 @@ Step 1) Setup phpunit.xml to enable SpeedTrap, but disable slowness profiling by
-
+
```
@@ -192,7 +184,7 @@ The easiest way to set environment variables for the script `simple-phpunit` is
-
+
```
diff --git a/composer.json b/composer.json
index 246098d..18450f2 100644
--- a/composer.json
+++ b/composer.json
@@ -19,9 +19,11 @@
}
],
"require": {
- "php": ">=7.2",
- "phpunit/phpunit": "^8.0 || ^9.0"
+ "php": "^8.1",
+ "phpunit/phpunit": "dev-main#e7dcb0e as 10.0.0"
},
+ "minimum-stability": "dev",
+ "prefer-stable": true,
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 08392a5..6b86c76 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -2,7 +2,7 @@
@@ -19,18 +19,10 @@
-
-
-
-
- 500
-
-
- 5
-
-
-
-
+
+
+
+
diff --git a/src/PreparedTest.php b/src/PreparedTest.php
new file mode 100644
index 0000000..68d1126
--- /dev/null
+++ b/src/PreparedTest.php
@@ -0,0 +1,26 @@
+test;
+ }
+
+ public function start(): Event\Telemetry\HRTime
+ {
+ return $this->start;
+ }
+}
diff --git a/src/RecordThatTestHasBeenPrepared.php b/src/RecordThatTestHasBeenPrepared.php
new file mode 100644
index 0000000..4959f3a
--- /dev/null
+++ b/src/RecordThatTestHasBeenPrepared.php
@@ -0,0 +1,22 @@
+speedTrap->recordThatTestHasBeenPrepared(
+ $event->test(),
+ $event->telemetryInfo()->time(),
+ );
+ }
+}
diff --git a/src/RecordThatTestHasPassed.php b/src/RecordThatTestHasPassed.php
new file mode 100644
index 0000000..f912811
--- /dev/null
+++ b/src/RecordThatTestHasPassed.php
@@ -0,0 +1,22 @@
+speedTrap->recordThatTestHasPassed(
+ $event->test(),
+ $event->telemetryInfo()->time(),
+ );
+ }
+}
diff --git a/src/ShowSlowTests.php b/src/ShowSlowTests.php
new file mode 100644
index 0000000..91db976
--- /dev/null
+++ b/src/ShowSlowTests.php
@@ -0,0 +1,19 @@
+speedTrap->showSlowTests();
+ }
+}
diff --git a/src/SpeedTrap.php b/src/SpeedTrap.php
index 9b84d2c..30e2230 100644
--- a/src/SpeedTrap.php
+++ b/src/SpeedTrap.php
@@ -3,35 +3,21 @@
namespace JohnKary\PHPUnit\Extension;
-use PHPUnit\Runner\AfterLastTestHook;
-use PHPUnit\Runner\AfterSuccessfulTestHook;
-use PHPUnit\Runner\BeforeFirstTestHook;
-use PHPUnit\Util\Test as TestUtil;
+use PHPUnit\Event;
+use PHPUnit\Metadata;
/**
* A PHPUnit Extension that exposes your slowest running tests by outputting
* results directly to the console.
*/
-class SpeedTrap implements AfterSuccessfulTestHook, BeforeFirstTestHook, AfterLastTestHook
+class SpeedTrap
{
/**
- * Slowness profiling enabled by default. Set to false to disable profiling
- * and reporting.
+ * A map of test identifiers to PreparedTest objects, for all tests that have been prepared, but not yet passed.
*
- * Use environment variable "PHPUNIT_SPEEDTRAP" set to value "disabled" to
- * disable profiling.
- *
- * @var boolean
- */
- protected $enabled = true;
-
- /**
- * Internal tracking for test suites.
- *
- * Increments as more suites are run, then decremented as they finish. All
- * suites have been run when returns to 0.
+ * @var array
*/
- protected $suites = 0;
+ private array $preparedTests = [];
/**
* Test execution time (milliseconds) after which a test will be considered
@@ -55,24 +41,44 @@ class SpeedTrap implements AfterSuccessfulTestHook, BeforeFirstTestHook, AfterLa
*/
protected $slow = [];
- public function __construct(array $options = [])
- {
- $this->enabled = getenv('PHPUNIT_SPEEDTRAP') === 'disabled' ? false : true;
- $this->loadOptions($options);
+ public function __construct(
+ int $slowThreshold,
+ int $reportLength,
+ ) {
+ $this->slowThreshold = $slowThreshold;
+ $this->reportLength = $reportLength;
}
- /**
- * A test successfully ended.
- *
- * @param string $test
- * @param float $time
- */
- public function executeAfterSuccessfulTest(string $test, float $time): void
- {
- if (!$this->enabled) return;
+ public function recordThatTestHasBeenPrepared(
+ Event\Code\Test $test,
+ Event\Telemetry\HRTime $start
+ ): void {
+ if (array_key_exists($test->id(), $this->preparedTests)) {
+ throw new \RuntimeException('This should not happen.');
+ }
+
+ $this->preparedTests[$test->id()] = new PreparedTest(
+ $test,
+ $start
+ );
+ }
+
+ public function recordThatTestHasPassed(
+ Event\Code\Test $test,
+ Event\Telemetry\HRTime $end
+ ): void {
+ if (!array_key_exists($test->id(), $this->preparedTests)) {
+ throw new \RuntimeException('This should not happen.');
+ }
+
+ $preparedTest = $this->preparedTests[$test->id()];
+
+ unset($this->preparedTests[$test->id()]);
+
+ $duration = $end->duration($preparedTest->start());
- $timeMS = $this->toMilliseconds($time);
+ $timeMS = $this->toMilliseconds($duration->asFloat());
$threshold = $this->getSlowThreshold($test);
if ($this->isSlow($timeMS, $threshold)) {
@@ -80,26 +86,12 @@ public function executeAfterSuccessfulTest(string $test, float $time): void
}
}
- /**
- * A test suite started.
- */
- public function executeBeforeFirstTest(): void
- {
- if (!$this->enabled) return;
-
- $this->suites++;
- }
-
/**
* A test suite ended.
*/
- public function executeAfterLastTest(): void
+ public function showSlowTests(): void
{
- if (!$this->enabled) return;
-
- $this->suites--;
-
- if (0 === $this->suites && $this->hasSlowTests()) {
+ if ($this->hasSlowTests()) {
arsort($this->slow); // Sort longest running tests to the top
$this->renderHeader();
@@ -124,7 +116,7 @@ protected function isSlow(int $time, int $slowThreshold): bool
*
* @param int $time Test execution time that was considered slow, in milliseconds
*/
- protected function addSlowTest(string $test, int $time): void
+ protected function addSlowTest(Event\Code\Test $test, int $time): void
{
$label = $this->makeLabel($test);
@@ -153,9 +145,15 @@ protected function toMilliseconds(float $time): int
*
* vendor/bin/phpunit --filter 'JohnKary\\PHPUnit\\Extension\\Tests\\SomeSlowTest::testWithDataProvider with data set "Rock"'
*/
- protected function makeLabel(string $test): string
+ protected function makeLabel(Event\Code\Test $test): string
{
- list($class, $testName) = explode('::', $test);
+ if (!$test->isTestMethod()) {
+ return $test->name();
+ }
+
+ /** @var Event\Code\TestMethod $test */
+ $class = $test->className();
+ $testName = $test->methodName();
// Remove argument list from end of string that is appended
// by default \PHPUnit\Framework\TestCase->toString() so slowness report
@@ -225,15 +223,6 @@ protected function renderFooter(): void
}
}
- /**
- * Populate options into class internals.
- */
- protected function loadOptions(array $options): void
- {
- $this->slowThreshold = $options['slowThreshold'] ?? 500;
- $this->reportLength = $options['reportLength'] ?? 10;
- }
-
/**
* Calculate slow test threshold for given test. A TestCase may override the
* suite-wide slowness threshold by using the annotation {@slowThreshold}
@@ -247,11 +236,20 @@ protected function loadOptions(array $options): void
* public function testLongRunningProcess() {}
*
*/
- protected function getSlowThreshold(string $test): int
+ protected function getSlowThreshold(Event\Code\Test $test): int
{
- list($class, $testName) = explode('::', $test);
- $ann = TestUtil::parseTestMethodAnnotations($class, $testName);
+ if (!$test->isTestMethod()) {
+ return $this->slowThreshold;
+ }
+
+ /** @var Event\Code\TestMethod $test */
+ $docBlock = Metadata\Annotation\Parser\Registry::getInstance()->forMethod(
+ $test->className(),
+ $test->methodName()
+ );
+
+ $ann = $docBlock->symbolAnnotations();
- return isset($ann['method']['slowThreshold'][0]) ? (int) $ann['method']['slowThreshold'][0] : $this->slowThreshold;
+ return isset($ann['slowThreshold'][0]) ? (int) $ann['slowThreshold'][0] : $this->slowThreshold;
}
}
diff --git a/src/SpeedTrapExtension.php b/src/SpeedTrapExtension.php
new file mode 100644
index 0000000..1b69b7e
--- /dev/null
+++ b/src/SpeedTrapExtension.php
@@ -0,0 +1,43 @@
+has('slowThreshold')) {
+ $slowThreshold = (int) $parameters->get('slowThreshold');
+ }
+
+ $reportLength = 10;
+
+ if ($parameters->has('reportLength')) {
+ $reportLength = (int) $parameters->get('reportLength');
+ }
+
+ $speedTrap = new SpeedTrap(
+ $slowThreshold,
+ $reportLength
+ );
+
+ $facade->registerSubscribers(
+ new RecordThatTestHasBeenPrepared($speedTrap),
+ new RecordThatTestHasPassed($speedTrap),
+ new ShowSlowTests($speedTrap),
+ );
+ }
+}