Skip to content

Commit

Permalink
Merge pull request #367 from HypeMC/add-maximumduration-attribute
Browse files Browse the repository at this point in the history
Add `#[MaximumDuration]` attribute
  • Loading branch information
localheinz committed Nov 27, 2023
2 parents 56d3a10 + 416eb76 commit 207ad11
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

For a full diff see [`2.4.0...main`][2.4.0...main].

### Added

- Added `Attribute\MaximumDuration` to allow configuration of maximum duration with attributes on test method level ([#367]), by [@HypeMC]

## [`2.4.0`][2.4.0]

For a full diff see [`2.3.2...2.4.0`][2.3.2...2.4.0].
Expand Down Expand Up @@ -195,5 +199,7 @@ For a full diff see [`7afa59c...1.0.0`][7afa59c...1.0.0].
[#354]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/354
[#355]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/355
[#357]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/357
[#367]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/367

[@HypeMC]: https://github.com/HypeMC
[@localheinz]: https://github.com/localheinz
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,34 +157,47 @@ The following example configures the maximum count of slow tests to three, and t

#### Configuring the maximum duration per test case

You can configure the maximum duration for a single test case with a `@maximumDuration` (or `@slowThreshold`) annotation in the DocBlock.
You can configure the maximum duration for a single test case with

The following example configures the maximum durations for single test cases to 5.000 and 4.000 ms:
- an `Attribute\MaximumDuration` attribute
- a `@maximumDuration` annotation in the DocBlock
- a `@slowThreshold` annotation in the DocBlock

The following example configures the maximum durations for single test cases to 5.000 ms, 4.000 ms, and 3.000 ms:

```php
<?php

declare(strict_types=1);

use PHPUnit\Framework;
use Ergebnis\PHPUnit\SlowTestDetector;

final class ExtraSlowTest extends Framework\TestCase
{
/**
* @maximumDuration 5000
*/
#[SlowTestDetector\Attribute\MaximumDuration(5000)]
public function testExtraExtraSlow(): void
{
// ...
}

/**
* @slowThreshold 4000
* @maximumDuration 4000
*/
public function testAlsoQuiteSlow(): void
{
// ...
}

/**
* @slowThreshold 3000
*/
public function testQuiteSlow(): void
{
// ...
}
}
```

Expand Down
35 changes: 35 additions & 0 deletions src/Attribute/MaximumDuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2021-2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpunit-slow-test-detector
*/

namespace Ergebnis\PHPUnit\SlowTestDetector\Attribute;

use Ergebnis\PHPUnit\SlowTestDetector\Exception;

#[\Attribute(\Attribute::TARGET_METHOD)]
final class MaximumDuration
{
/**
* @throws Exception\InvalidMilliseconds
*/
public function __construct(private readonly int $milliseconds)
{
if (0 >= $milliseconds) {
throw Exception\InvalidMilliseconds::notGreaterThanZero($milliseconds);
}
}

public function milliseconds(): int
{
return $this->milliseconds;
}
}
41 changes: 40 additions & 1 deletion src/Subscriber/TestPassedSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Ergebnis\PHPUnit\SlowTestDetector\Subscriber;

use Ergebnis\PHPUnit\SlowTestDetector\Attribute;
use Ergebnis\PHPUnit\SlowTestDetector\Collector;
use Ergebnis\PHPUnit\SlowTestDetector\Duration;
use Ergebnis\PHPUnit\SlowTestDetector\SlowTest;
Expand Down Expand Up @@ -64,6 +65,44 @@ public function notify(Event\Test\Passed $event): void
}

private function resolveMaximumDuration(Event\Code\Test $test): Duration
{
$maximumDurationFromAttribute = self::resolveMaximumDurationFromAttribute($test);

if ($maximumDurationFromAttribute instanceof Duration) {
return $maximumDurationFromAttribute;
}

$maximumDurationFromAnnotation = self::resolveMaximumDurationFromAnnotation($test);

if ($maximumDurationFromAnnotation instanceof Duration) {
return $maximumDurationFromAnnotation;
}

return $this->maximumDuration;
}

private static function resolveMaximumDurationFromAttribute(Event\Code\Test $test): ?Duration
{
/** @var Event\Code\TestMethod $test */
$methodReflection = new \ReflectionMethod(
$test->className(),
$test->methodName(),
);

$attributeReflections = $methodReflection->getAttributes(Attribute\MaximumDuration::class);

if ([] !== $attributeReflections) {
$attributeReflection = \reset($attributeReflections);

$attribute = $attributeReflection->newInstance();

return Duration::fromMilliseconds($attribute->milliseconds());
}

return null;
}

private static function resolveMaximumDurationFromAnnotation(Event\Code\Test $test): ?Duration
{
$annotations = [
'maximumDuration',
Expand Down Expand Up @@ -96,6 +135,6 @@ private function resolveMaximumDuration(Event\Code\Test $test): Duration
return Duration::fromMilliseconds((int) $maximumDuration);
}

return $this->maximumDuration;
return null;
}
}
40 changes: 40 additions & 0 deletions test/EndToEnd/Version10/MaximumDuration/Fifty/SleeperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

namespace Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty;

use Ergebnis\PHPUnit\SlowTestDetector\Attribute;
use Ergebnis\PHPUnit\SlowTestDetector\Test;
use PHPUnit\Framework;

Expand Down Expand Up @@ -167,4 +168,43 @@ public function testSleeperSleepsLongerThanMaximumDurationFromSlowThresholdAnnot

self::assertSame($milliseconds, $sleeper->milliseconds());
}

#[Attribute\MaximumDuration(140)]
public function testSleeperSleepsShorterThanMaximumDurationFromMaximumDurationAttribute(): void
{
$milliseconds = 130;

$sleeper = Test\Fixture\Sleeper::fromMilliseconds($milliseconds);

$sleeper->sleep();

self::assertSame($milliseconds, $sleeper->milliseconds());
}

#[Attribute\MaximumDuration(160)]
public function testSleeperSleepsLongerThanMaximumDurationFromMaximumDurationAttribute(): void
{
$milliseconds = 160;

$sleeper = Test\Fixture\Sleeper::fromMilliseconds($milliseconds);

$sleeper->sleep();

self::assertSame($milliseconds, $sleeper->milliseconds());
}

/**
* @maximumDuration 20
*/
#[Attribute\MaximumDuration(50)]
public function testSleeperSleepsShorterThanMaximumDurationFromMaximumDurationAttributeWhenMaximumDurationAnnotationIsPresent(): void
{
$milliseconds = 40;

$sleeper = Test\Fixture\Sleeper::fromMilliseconds($milliseconds);

$sleeper->sleep();

self::assertSame($milliseconds, $sleeper->milliseconds());
}
}
13 changes: 7 additions & 6 deletions test/EndToEnd/Version10/MaximumDuration/Fifty/test.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ Runtime: %s
Configuration: %Stest/EndToEnd/Version10/MaximumDuration/Fifty/phpunit.xml
Random Seed: %s

.......... 10 / 10 (100%)
............. 13 / 13 (100%)

Detected 6 tests that took longer than expected.
Detected 7 tests that took longer than expected.

1. 0.2%s (0.200) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsLongerThanMaximumDurationFromSlowThresholdAnnotation
2. 0.2%s (0.180) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsLongerThanMaximumDurationFromMaximumDurationAnnotationWhenSlowThresholdAnnotationIsPresentBeforeMaximumDuration
3. 0.1%s (0.160) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsLongerThanMaximumDurationFromMaximumDurationAnnotationWhenSlowThresholdAnnotationIsPresentAfterMaximumDuration
4. 0.1%s (0.150) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsLongerThanMaximumDurationFromMaximumDurationAnnotation
5. 0.1%s (0.050) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsWithDocBlockWithMaximumDurationAnnotationWhereValueIsNotAnInt
6. 0.0%s (0.050) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsWithDocBlockWithoutSlowThresholdAnnotation
4. 0.1%s (0.160) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsLongerThanMaximumDurationFromMaximumDurationAttribute
5. 0.1%s (0.150) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsLongerThanMaximumDurationFromMaximumDurationAnnotation
6. 0.1%s (0.050) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsWithDocBlockWithMaximumDurationAnnotationWhereValueIsNotAnInt
7. 0.0%s (0.050) Ergebnis\PHPUnit\SlowTestDetector\Test\EndToEnd\Version10\MaximumDuration\Fifty\SleeperTest::testSleeperSleepsWithDocBlockWithoutSlowThresholdAnnotation

Time: %s, Memory: %s

OK (10 tests, 10 assertions)
OK (13 tests, 13 assertions)
45 changes: 45 additions & 0 deletions test/Unit/Attribute/MaximumDurationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2021-2023 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpunit-slow-test-detector
*/

namespace Ergebnis\PHPUnit\SlowTestDetector\Test\Unit\Attribute;

use Ergebnis\DataProvider;
use Ergebnis\PHPUnit\SlowTestDetector\Attribute;
use Ergebnis\PHPUnit\SlowTestDetector\Duration;
use Ergebnis\PHPUnit\SlowTestDetector\Exception;
use Ergebnis\PHPUnit\SlowTestDetector\Test;
use PHPUnit\Framework;

#[Framework\Attributes\CoversClass(Attribute\MaximumDuration::class)]
final class MaximumDurationTest extends Framework\TestCase
{
use Test\Util\Helper;

#[Framework\Attributes\DataProviderExternal(DataProvider\IntProvider::class, 'lessThanZero')]
#[Framework\Attributes\DataProviderExternal(DataProvider\IntProvider::class, 'zero')]
public function testConstructorRejectsInvalidValue(int $milliseconds): void
{
$this->expectException(Exception\InvalidMilliseconds::class);

Duration::fromMilliseconds($milliseconds);
}

public function testConstructorSetsValue(): void
{
$milliseconds = self::faker()->numberBetween(1);

$maximumDuration = new Attribute\MaximumDuration($milliseconds);

self::assertSame($milliseconds, $maximumDuration->milliseconds());
}
}

0 comments on commit 207ad11

Please sign in to comment.