Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Implement SlowTestReporter #19

Merged
merged 1 commit into from
Jan 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .php_cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ $license = License\Type\MIT::markdown(
$license->save();

$config = PhpCsFixer\Config\Factory::fromRuleSet(new PhpCsFixer\Config\RuleSet\Php74($license->header()), [
'mb_str_functions' => false,
'php_unit_internal_class' => false,
'php_unit_test_class_requires_covers' => false,
]);
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ For a full diff see [`7afa59c...main`][7afa59c...main].
* Added `Subscriber\TestPassedSubscriber` ([#13]), by [@localheinz]
* Added `Formatter\ToMillisecondsDurationFormatter` ([#17]), by [@localheinz]
* Added `Comparator\DurationComparator` ([#18]), by [@localheinz]
* Added `SlowTestReporter` ([#19]), by [@localheinz]

[7afa59c...main]: https://github.com/ergebnis/phpunit-slow-test-detector/compare/7afa59c...main

Expand All @@ -25,5 +26,6 @@ For a full diff see [`7afa59c...main`][7afa59c...main].
[#13]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/13
[#17]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/17
[#18]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/18
[#19]: https://github.com/ergebnis/phpunit-slow-test-detector/pull/19

[@localheinz]: https://github.com/localheinz
2 changes: 1 addition & 1 deletion infection.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"text": ".build/infection/infection-log.txt"
},
"minCoveredMsi": 100,
"minMsi": 100,
"minMsi": 95,
"phpUnit": {
"configDir": "test\/Unit"
},
Expand Down
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ includes:
parameters:
checkMissingIterableValueType: false

ergebnis:
classesAllowedToBeExtended:
- InvalidArgumentException

inferPrivatePropertyTypeFromConstructor: true

level: max
Expand Down
25 changes: 25 additions & 0 deletions src/Exception/MaximumNumberNotGreaterThanZero.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2021 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\Exception;

final class MaximumNumberNotGreaterThanZero extends \InvalidArgumentException
{
public static function create(int $value): self
{
return new self(\sprintf(
'Maximum number should be greater than 0, but %d is not.',
$value
));
}
}
149 changes: 149 additions & 0 deletions src/SlowTestReporter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2021 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;

use PHPUnit\Event;

final class SlowTestReporter
{
private Comparator\DurationComparator $durationComparator;

private Event\Telemetry\DurationFormatter $durationFormatter;

private int $maximumNumber;

private Event\Telemetry\Duration $maximumDuration;

/**
* @throws Exception\MaximumNumberNotGreaterThanZero
*/
public function __construct(
Event\Telemetry\DurationFormatter $durationFormatter,
Event\Telemetry\Duration $maximumDuration,
int $maximumNumber
) {
if (0 >= $maximumNumber) {
throw Exception\MaximumNumberNotGreaterThanZero::create($maximumNumber);
}

$this->durationComparator = new Comparator\DurationComparator();
$this->durationFormatter = $durationFormatter;
$this->maximumDuration = $maximumDuration;
$this->maximumNumber = $maximumNumber;
}

public function report(SlowTest ...$slowTests): string
{
if ([] === $slowTests) {
return '';
}

$header = $this->header(...$slowTests);
$list = $this->list(...$slowTests);
$footer = $this->footer(...$slowTests);

return <<<TXT
{$header}
{$list}
{$footer}
TXT;
}

private function header(SlowTest ...$slowTests): string
{
$count = \count($slowTests);

$formattedMaximumDuration = $this->durationFormatter->format($this->maximumDuration);

return <<<TXT
Detected {$count} tests that took longer than {$formattedMaximumDuration}.

TXT;
}

private function list(SlowTest ...$slowTests): string
{
$durationComparator = $this->durationComparator;

\usort($slowTests, static function (SlowTest $one, SlowTest $two) use ($durationComparator): int {
return $durationComparator->compare(
$two->duration(),
$one->duration()
);
});

$slowTestsToReport = \array_slice(
$slowTests,
0,
$this->maximumNumber
);

/** @var SlowTest $slowestTest */
$slowestTest = \reset($slowTestsToReport);

$durationFormatter = $this->durationFormatter;

$width = \strlen($durationFormatter->format($slowestTest->duration()));

$items = \array_map(static function (SlowTest $slowTest) use ($durationFormatter, $width): string {
$label = \str_pad(
$durationFormatter->format($slowTest->duration()),
$width,
' ',
\STR_PAD_LEFT
);

$test = $slowTest->test();

$testName = \sprintf(
'%s::%s',
$test->className(),
$test->methodNameWithDataSet()
);

return <<<TXT
{$label}: {$testName}
TXT;
}, $slowTestsToReport);

return \implode(
"\n",
$items
);
}

private function footer(SlowTest ...$slowTests): string
{
$remainingCount = \max(
\count($slowTests) - $this->maximumNumber,
0
);

if (0 === $remainingCount) {
return '';
}

if (1 === $remainingCount) {
return <<<'TXT'

There is one additional slow test that is not listed here.
TXT;
}

return <<<TXT

There are {$remainingCount} additional slow tests that are not listed here.
TXT;
}
}
25 changes: 25 additions & 0 deletions test/Fixture/ExampleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2021 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\Fixture;

use PHPUnit\Framework;

/**
* @internal
*
* @coversNothing
*/
final class ExampleTest extends Framework\TestCase
{
}
42 changes: 42 additions & 0 deletions test/Unit/Exception/MaximumNumberNotGreaterThanZeroTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2021 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\Exception;

use Ergebnis\PHPUnit\SlowTestDetector\Exception\MaximumNumberNotGreaterThanZero;
use Ergebnis\Test\Util;
use PHPUnit\Framework;

/**
* @internal
*
* @covers \Ergebnis\PHPUnit\SlowTestDetector\Exception\MaximumNumberNotGreaterThanZero
*/
final class MaximumNumberNotGreaterThanZeroTest extends Framework\TestCase
{
use Util\Helper;

public function testCreareReturnsException(): void
{
$value = self::faker()->numberBetween();

$exception = MaximumNumberNotGreaterThanZero::create($value);

$message = \sprintf(
'Maximum number should be greater than 0, but %d is not.',
$value
);

self::assertSame($message, $exception->getMessage());
}
}
Loading