From ed96c3e89eb3b49591ce57ef75316c8e40d41106 Mon Sep 17 00:00:00 2001 From: Edward Surov Date: Thu, 22 Dec 2022 19:41:01 +0200 Subject: [PATCH] Extension rewritten for PHPUnit 10 (#85) --- .github/workflows/build.yml | 18 +- README.md | 28 +- composer.json | 25 +- phpunit.report.xml | 8 +- phpunit.xml.dist | 4 +- psalm.xml.dist | 4 + src/AllureExtension.php | 140 ++------- src/Event/TestConsideredRiskySubscriber.php | 33 +++ src/Event/TestErroredSubscriber.php | 33 +++ src/Event/TestFailedSubscriber.php | 33 +++ src/Event/TestFinishedSubscriber.php | 34 +++ src/Event/TestMarkedIncompleteSubscriber.php | 33 +++ src/Event/TestPassedSubscriber.php | 33 +++ .../TestPreparationStartedSubscriber.php | 33 +++ src/Event/TestPreparedSubscriber.php | 33 +++ src/Event/TestSkippedSubscriber.php | 33 +++ src/Event/TestWarningTriggeredSubscriber.php | 33 +++ src/ExceptionDetailsTrait.php | 2 +- src/Internal/Config.php | 2 +- src/Internal/TestInfo.php | 12 +- src/Internal/TestLifecycle.php | 12 +- src/Internal/TestRunInfo.php | 12 +- src/Internal/TestStartInfo.php | 4 +- src/Internal/TestUpdater.php | 2 +- test/report/Generate/NegativeTest.php | 19 +- test/report/Generate/RetriesTest.php | 92 ------ test/unit/AllureAdapterTest.php | 22 +- test/unit/AllureExtensionTest.php | 261 ----------------- test/unit/Event/EventTestTrait.php | 266 ++++++++++++++++++ .../TestConsideredRiskySubscriberTest.php | 58 ++++ test/unit/Event/TestErroredSubscriberTest.php | 59 ++++ test/unit/Event/TestFailedSubscriberTest.php | 59 ++++ .../unit/Event/TestFinishedSubscriberTest.php | 64 +++++ .../TestMarkedIncompleteSubscriberTest.php | 58 ++++ test/unit/Event/TestPassedSubscriberTest.php | 57 ++++ .../TestPreparationStartedSubscriberTest.php | 58 ++++ .../unit/Event/TestPreparedSubscriberTest.php | 58 ++++ test/unit/Event/TestSkippedSubscriberTest.php | 58 ++++ .../TestWarningTriggeredSubscriberTest.php | 58 ++++ test/unit/ExceptionDetailsTraitTest.php | 5 +- test/unit/Internal/ConfigTest.php | 42 +-- .../Internal/DefaultThreadDetectorTest.php | 5 +- test/unit/Internal/TestInfoTest.php | 36 +-- test/unit/Internal/TestRunInfoTest.php | 10 +- test/unit/Internal/TestStartInfoTest.php | 5 +- 45 files changed, 1337 insertions(+), 617 deletions(-) create mode 100644 src/Event/TestConsideredRiskySubscriber.php create mode 100644 src/Event/TestErroredSubscriber.php create mode 100644 src/Event/TestFailedSubscriber.php create mode 100644 src/Event/TestFinishedSubscriber.php create mode 100644 src/Event/TestMarkedIncompleteSubscriber.php create mode 100644 src/Event/TestPassedSubscriber.php create mode 100644 src/Event/TestPreparationStartedSubscriber.php create mode 100644 src/Event/TestPreparedSubscriber.php create mode 100644 src/Event/TestSkippedSubscriber.php create mode 100644 src/Event/TestWarningTriggeredSubscriber.php delete mode 100644 test/report/Generate/RetriesTest.php delete mode 100644 test/unit/AllureExtensionTest.php create mode 100644 test/unit/Event/EventTestTrait.php create mode 100644 test/unit/Event/TestConsideredRiskySubscriberTest.php create mode 100644 test/unit/Event/TestErroredSubscriberTest.php create mode 100644 test/unit/Event/TestFailedSubscriberTest.php create mode 100644 test/unit/Event/TestFinishedSubscriberTest.php create mode 100644 test/unit/Event/TestMarkedIncompleteSubscriberTest.php create mode 100644 test/unit/Event/TestPassedSubscriberTest.php create mode 100644 test/unit/Event/TestPreparationStartedSubscriberTest.php create mode 100644 test/unit/Event/TestPreparedSubscriberTest.php create mode 100644 test/unit/Event/TestSkippedSubscriberTest.php create mode 100644 test/unit/Event/TestWarningTriggeredSubscriberTest.php diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6297f34..fe82706 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,9 +17,9 @@ jobs: fail-fast: false matrix: php-version: - - "8.0" - "8.1" - "8.2" + - "8.3" os: - ubuntu-latest - windows-latest @@ -29,7 +29,7 @@ jobs: - "--prefer-lowest" steps: - name: Checkout - uses: actions/checkout@v3.5.0 + uses: actions/checkout@v3 - name: Validate composer.json and composer.lock run: composer validate @@ -49,19 +49,9 @@ jobs: ${{ matrix.composer-options }} - name: Run tests - if: ${{ matrix.os != 'windows-latest' && matrix.php-version != '8.2' }} + if: ${{ matrix.os != 'windows-latest' }} run: composer test - name: Run tests (windows) - if: ${{ matrix.os == 'windows-latest' && matrix.php-version != '8.2' }} - run: composer test-windows - - - name: Run tests (experimental) - if: ${{ matrix.os != 'windows-latest' && matrix.php-version == '8.2' }} - continue-on-error: true - run: composer test - - - name: Run tests (windows, experimental) - if: ${{ matrix.os == 'windows-latest' && matrix.php-version == '8.2' }} - continue-on-error: true + if: ${{ matrix.os == 'windows-latest' }} run: composer test-windows diff --git a/README.md b/README.md index 1262db2..bd381bc 100644 --- a/README.md +++ b/README.md @@ -34,25 +34,25 @@ This adapter only generates JSON files containing information about tests. See [ ## Installation && Usage **Note:** this adapter supports Allure 2.x.x only. + +Supported PHP versions: 8.1-8.3. + In order to use this adapter you need to add a new dependency to your **composer.json** file: ``` { "require": { - "php": "^8", - "allure-framework/allure-phpunit": "^2" + "php": "^8.1", + "allure-framework/allure-phpunit": "^3" } } ``` Then add Allure test listener in **phpunit.xml** file: ```xml - - - - - config/allure.config.php - - + + + + ``` Config is common PHP file that should return an array: @@ -84,17 +84,17 @@ After running PHPUnit tests a new folder will be created (**build/allure-results This adapter comes with a set of PHP annotations and traits allowing to use main Allure features. ### Human-readable test class or test method title -In order to add such title to any test class or [test case](https://github.com/allure-framework/allure1/wiki/Glossary#test-case) method you need to annotate it with **#[Title]** annotation: +In order to add such title to any test class or [test case](https://github.com/allure-framework/allure1/wiki/Glossary#test-case) method you need to annotate it with **#[DisplayName]** annotation: ```php namespace Example\Tests; use PHPUnit\Framework\TestCase; -use Qameta\Allure\Attribute\Title; +use Qameta\Allure\Attribute\DisplayName; -#[Title("Human-readable test class title")] +#[DisplayName("Human-readable test class title")] class SomeTest extends TestCase { - #[Title("Human-readable test method title")] + #[DisplayName("Human-readable test method title")] public function testCaseMethod(): void { //Some implementation here... @@ -251,7 +251,7 @@ class SomeTest extends TestCase Title("Second step"), Parameter("param2", "value2"), ] - private function stepTwo() + private function stepTwo(): void { //Some implementation here... } diff --git a/composer.json b/composer.json index 61bd148..44d6481 100644 --- a/composer.json +++ b/composer.json @@ -29,18 +29,19 @@ "source": "https://github.com/allure-framework/allure-phpunit" }, "require": { - "php": "^8", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0", "allure-framework/allure-php-commons": "^2", - "phpunit/phpunit": "^9" + "phpunit/phpunit": "^10" }, "require-dev": { - "brianium/paratest": "^6.8", + "brianium/paratest": "^7", "psalm/plugin-phpunit": "^0.18.4", - "squizlabs/php_codesniffer": "^3.7.1", - "vimeo/psalm": "^5.4" + "squizlabs/php_codesniffer": "^3.7.2", + "vimeo/psalm": "^5.15" }, "conflict": { - "amphp/byte-stream": "<1.5.1" + "amphp/byte-stream": "<1.5.1", + "brianium/paratest": "<7.0.3" }, "autoload": { "psr-4": { @@ -63,27 +64,23 @@ "test-report": [ "@clear-allure-results", "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=positive", - "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=negative; exit 0", - "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=retries --repeat=3; exit 0" + "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=negative; exit 0" ], "test-report-windows": [ "@clear-allure-results", "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=positive", - "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=negative & exit 0", - "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=retries --repeat=3 & exit 0" + "vendor/bin/paratest --processes=3 --configuration=phpunit.report.xml --testsuite=negative & exit 0" ], "test-psalm": "vendor/bin/psalm --shepherd", "test": [ "@test-cs", "@test-unit", - "@test-report", - "@test-psalm" + "@test-report" ], "test-windows": [ "@test-cs", "@test-unit", - "@test-report-windows", - "@test-psalm" + "@test-report-windows" ] } } diff --git a/phpunit.report.xml b/phpunit.report.xml index 20654ab..60298d5 100644 --- a/phpunit.report.xml +++ b/phpunit.report.xml @@ -1,23 +1,19 @@ test/report/Generate test/report/Generate/NegativeTest.php - test/report/Generate/RetriesTest.php test/report/Generate/NegativeTest.php - - test/report/Generate/RetriesTest.php - - + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4660606..f7ce70a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ @@ -9,7 +9,7 @@ test/unit/ - + src/ diff --git a/psalm.xml.dist b/psalm.xml.dist index ab032bb..828d139 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -1,6 +1,10 @@ diff --git a/src/AllureExtension.php b/src/AllureExtension.php index f4ed380..5dda14d 100644 --- a/src/AllureExtension.php +++ b/src/AllureExtension.php @@ -4,18 +4,12 @@ namespace Qameta\Allure\PHPUnit; -use PHPUnit\Runner\AfterIncompleteTestHook; -use PHPUnit\Runner\AfterRiskyTestHook; -use PHPUnit\Runner\AfterSkippedTestHook; -use PHPUnit\Runner\AfterSuccessfulTestHook; -use PHPUnit\Runner\AfterTestErrorHook; -use PHPUnit\Runner\AfterTestFailureHook; -use PHPUnit\Runner\AfterTestHook; -use PHPUnit\Runner\AfterTestWarningHook; -use PHPUnit\Runner\BeforeTestHook; +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; use Qameta\Allure\Allure; use Qameta\Allure\Model\LinkType; -use Qameta\Allure\Model\Status; use Qameta\Allure\PHPUnit\Internal\Config; use Qameta\Allure\PHPUnit\Internal\ConfigInterface; use Qameta\Allure\PHPUnit\Internal\DefaultThreadDetector; @@ -29,37 +23,20 @@ use const DIRECTORY_SEPARATOR; -final class AllureExtension implements - BeforeTestHook, - AfterTestHook, - AfterTestFailureHook, - AfterTestErrorHook, - AfterIncompleteTestHook, - AfterSkippedTestHook, - AfterTestWarningHook, - AfterRiskyTestHook, - AfterSuccessfulTestHook +final class AllureExtension implements Extension { private const DEFAULT_OUTPUT_DIRECTORY = 'build' . DIRECTORY_SEPARATOR . 'allure-results'; private const DEFAULT_CONFIG_FILE = 'config' . DIRECTORY_SEPARATOR . 'allure.config.php'; - private TestLifecycleInterface $testLifecycle; - public function __construct( - string|array|ConfigInterface|TestLifecycleInterface|null $configOrTestLifecycle = null, + private readonly ?TestLifecycleInterface $testLifecycle = null, ) { - $this->testLifecycle = $configOrTestLifecycle instanceof TestLifecycleInterface - ? $configOrTestLifecycle - : $this->createTestLifecycle($configOrTestLifecycle); } - private function createTestLifecycle(string|array|ConfigInterface|null $configSource): TestLifecycleInterface + private function createTestLifecycle(?string $configSource): TestLifecycleInterface { - $config = $configSource instanceof ConfigInterface - ? $configSource - : $this->loadConfig($configSource); - + $config = new Config($this->loadConfigData($configSource)); $this->setupAllure($config); return new TestLifecycle( @@ -95,15 +72,6 @@ private function setupAllure(ConfigInterface $config): void } } - private function loadConfig(string|array|null $configSource): ConfigInterface - { - return new Config( - is_array($configSource) - ? $configSource - : $this->loadConfigData($configSource), - ); - } - private function loadConfigData(?string $configFile): array { $fileShouldExist = isset($configFile); @@ -121,80 +89,26 @@ private function loadConfigData(?string $configFile): array return []; } - public function executeBeforeTest(string $test): void - { - $this - ->testLifecycle - ->switchTo($test) - ->reset() - ->create() - ->updateInfo() - ->start(); - } - - public function executeAfterTest(string $test, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->stop() - ->updateRunInfo() - ->write(); - } - - public function executeAfterTestFailure(string $test, string $message, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->updateDetectedStatus($message, Status::failed(), Status::failed()); - } - - public function executeAfterTestError(string $test, string $message, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->updateDetectedStatus($message, Status::broken()); - } - - public function executeAfterIncompleteTest(string $test, string $message, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->updateStatus($message, Status::broken()); - } - - public function executeAfterSkippedTest(string $test, string $message, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->updateStatus($message, Status::skipped()); - } - public function executeAfterTestWarning(string $test, string $message, float $time): void + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void { - $this - ->testLifecycle - ->switchTo($test) - ->updateStatus($message, Status::broken()); - } - - public function executeAfterRiskyTest(string $test, string $message, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->updateStatus($message, Status::failed()); - } - - public function executeAfterSuccessfulTest(string $test, float $time): void - { - $this - ->testLifecycle - ->switchTo($test) - ->updateStatus(status: Status::passed()); + $configSource = $parameters->has('config') + ? $parameters->get('config') + : null; + + $testLifecycle = $this->testLifecycle ?? $this->createTestLifecycle($configSource); + + $facade->registerSubscribers( + new Event\TestPreparationStartedSubscriber($testLifecycle), + new Event\TestPreparedSubscriber($testLifecycle), + new Event\TestFinishedSubscriber($testLifecycle), + new Event\TestFailedSubscriber($testLifecycle), + new Event\TestErroredSubscriber($testLifecycle), + new Event\TestMarkedIncompleteSubscriber($testLifecycle), + new Event\TestSkippedSubscriber($testLifecycle), + new Event\TestWarningTriggeredSubscriber($testLifecycle), + new Event\TestConsideredRiskySubscriber($testLifecycle), + new Event\TestPassedSubscriber($testLifecycle), + ); } } diff --git a/src/Event/TestConsideredRiskySubscriber.php b/src/Event/TestConsideredRiskySubscriber.php new file mode 100644 index 0000000..b06bf08 --- /dev/null +++ b/src/Event/TestConsideredRiskySubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateStatus($event->message(), Status::failed()); + } +} diff --git a/src/Event/TestErroredSubscriber.php b/src/Event/TestErroredSubscriber.php new file mode 100644 index 0000000..01fc3b1 --- /dev/null +++ b/src/Event/TestErroredSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateDetectedStatus($event->throwable()->message(), Status::broken()); + } +} diff --git a/src/Event/TestFailedSubscriber.php b/src/Event/TestFailedSubscriber.php new file mode 100644 index 0000000..401b891 --- /dev/null +++ b/src/Event/TestFailedSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateDetectedStatus($event->throwable()->message(), Status::failed(), Status::failed()); + } +} diff --git a/src/Event/TestFinishedSubscriber.php b/src/Event/TestFinishedSubscriber.php new file mode 100644 index 0000000..2aded86 --- /dev/null +++ b/src/Event/TestFinishedSubscriber.php @@ -0,0 +1,34 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->stop() + ->updateRunInfo() + ->write(); + } +} diff --git a/src/Event/TestMarkedIncompleteSubscriber.php b/src/Event/TestMarkedIncompleteSubscriber.php new file mode 100644 index 0000000..9dc7289 --- /dev/null +++ b/src/Event/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateStatus($event->throwable()->message(), Status::broken()); + } +} diff --git a/src/Event/TestPassedSubscriber.php b/src/Event/TestPassedSubscriber.php new file mode 100644 index 0000000..3c07449 --- /dev/null +++ b/src/Event/TestPassedSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateStatus(status: Status::passed()); + } +} diff --git a/src/Event/TestPreparationStartedSubscriber.php b/src/Event/TestPreparationStartedSubscriber.php new file mode 100644 index 0000000..5955bd3 --- /dev/null +++ b/src/Event/TestPreparationStartedSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->reset() + ->create(); + } +} diff --git a/src/Event/TestPreparedSubscriber.php b/src/Event/TestPreparedSubscriber.php new file mode 100644 index 0000000..8eccb02 --- /dev/null +++ b/src/Event/TestPreparedSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateInfo() + ->start(); + } +} diff --git a/src/Event/TestSkippedSubscriber.php b/src/Event/TestSkippedSubscriber.php new file mode 100644 index 0000000..c572e9f --- /dev/null +++ b/src/Event/TestSkippedSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test->nameWithClass() : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method) + ->updateStatus($event->message(), Status::skipped()); + } +} diff --git a/src/Event/TestWarningTriggeredSubscriber.php b/src/Event/TestWarningTriggeredSubscriber.php new file mode 100644 index 0000000..a47e915 --- /dev/null +++ b/src/Event/TestWarningTriggeredSubscriber.php @@ -0,0 +1,33 @@ +test(); + $method = $test instanceof TestMethod ? $test : null; + if (!isset($method)) { + return; + } + + $this + ->testLifecycle + ->switchTo($method->nameWithClass()) + ->updateStatus($event->message(), Status::broken()); + } +} diff --git a/src/ExceptionDetailsTrait.php b/src/ExceptionDetailsTrait.php index 42972f9..c3b1b5b 100644 --- a/src/ExceptionDetailsTrait.php +++ b/src/ExceptionDetailsTrait.php @@ -8,7 +8,7 @@ trait ExceptionDetailsTrait { - protected function onNotSuccessfulTest(Throwable $t): void + protected function onNotSuccessfulTest(Throwable $t): never { AllureAdapter::getInstance()->setLastException($t); throw $t; diff --git a/src/Internal/Config.php b/src/Internal/Config.php index 6de063a..cf870ec 100644 --- a/src/Internal/Config.php +++ b/src/Internal/Config.php @@ -19,7 +19,7 @@ final class Config implements ConfigInterface { public function __construct( - private array $data, + private readonly array $data, ) { } diff --git a/src/Internal/TestInfo.php b/src/Internal/TestInfo.php index 3d448a8..8a8cea2 100644 --- a/src/Internal/TestInfo.php +++ b/src/Internal/TestInfo.php @@ -18,12 +18,12 @@ final class TestInfo * @param string|null $thread */ public function __construct( - private string $test, - private ?string $class, - private ?string $method, - private ?string $dataLabel, - private ?string $host, - private ?string $thread, + private readonly string $test, + private readonly ?string $class, + private readonly ?string $method, + private readonly ?string $dataLabel, + private readonly ?string $host, + private readonly ?string $thread, ) { } diff --git a/src/Internal/TestLifecycle.php b/src/Internal/TestLifecycle.php index e4dcdca..0053700 100644 --- a/src/Internal/TestLifecycle.php +++ b/src/Internal/TestLifecycle.php @@ -26,12 +26,12 @@ final class TestLifecycle implements TestLifecycleInterface private ?TestInfo $currentTest = null; public function __construct( - private AllureLifecycleInterface $lifecycle, - private ResultFactoryInterface $resultFactory, - private StatusDetectorInterface $statusDetector, - private ThreadDetectorInterface $threadDetector, - private AllureAdapterInterface $adapter, - private TestUpdaterInterface $testUpdater, + private readonly AllureLifecycleInterface $lifecycle, + private readonly ResultFactoryInterface $resultFactory, + private readonly StatusDetectorInterface $statusDetector, + private readonly ThreadDetectorInterface $threadDetector, + private readonly AllureAdapterInterface $adapter, + private readonly TestUpdaterInterface $testUpdater, ) { } diff --git a/src/Internal/TestRunInfo.php b/src/Internal/TestRunInfo.php index 20455b0..33a13b4 100644 --- a/src/Internal/TestRunInfo.php +++ b/src/Internal/TestRunInfo.php @@ -10,12 +10,12 @@ final class TestRunInfo { public function __construct( - private TestInfo $testInfo, - private string $uuid, - private ?string $rerunOf, - private int $runIndex, - private string $testCaseId, - private string $historyId, + private readonly TestInfo $testInfo, + private readonly string $uuid, + private readonly ?string $rerunOf, + private readonly int $runIndex, + private readonly string $testCaseId, + private readonly string $historyId, ) { } diff --git a/src/Internal/TestStartInfo.php b/src/Internal/TestStartInfo.php index 92aff73..d49597c 100644 --- a/src/Internal/TestStartInfo.php +++ b/src/Internal/TestStartInfo.php @@ -7,8 +7,8 @@ final class TestStartInfo { public function __construct( - private string $containerId, - private string $testId, + private readonly string $containerId, + private readonly string $testId, ) { } diff --git a/src/Internal/TestUpdater.php b/src/Internal/TestUpdater.php index d26a3e2..2321f85 100644 --- a/src/Internal/TestUpdater.php +++ b/src/Internal/TestUpdater.php @@ -26,7 +26,7 @@ class TestUpdater implements TestUpdaterInterface { public function __construct( - private LinkTemplateCollectionInterface $linkTemplates, + private readonly LinkTemplateCollectionInterface $linkTemplates, ) { } diff --git a/test/report/Generate/NegativeTest.php b/test/report/Generate/NegativeTest.php index 81c7ba1..fe68a69 100644 --- a/test/report/Generate/NegativeTest.php +++ b/test/report/Generate/NegativeTest.php @@ -4,6 +4,7 @@ namespace Qameta\Allure\PHPUnit\Test\Report\Generate; +use PHPUnit\Event; use PHPUnit\Framework\TestCase; use Qameta\Allure\Allure; use Qameta\Allure\Attribute\DisplayName; @@ -53,8 +54,19 @@ function () { #[DisplayName('Test that emits warning is reported as broken')] public function testWarning(): void { - /** @psalm-suppress InternalMethod */ - $this->addWarning('Warning message'); + /** + * @psalm-suppress InternalMethod + * @psalm-suppress InternalClass + * @psalm-suppress TooManyArguments + */ + Event\Facade::emitter()->testTriggeredWarning( + $this->valueObjectForEvents(), + "Test triggered warning", + __FILE__, + __LINE__, + false, + ); + self::assertTrue(true); } #[DisplayName('Skipped test is reported as skipped')] @@ -72,7 +84,6 @@ public function testIncomplete(): void #[DisplayName('Risky test is reported as failed')] public function testRisky(): void { - self::markAsRisky(); - $this->expectNotToPerformAssertions(); + // Not performing assertions makes test risky } } diff --git a/test/report/Generate/RetriesTest.php b/test/report/Generate/RetriesTest.php deleted file mode 100644 index dfb686c..0000000 --- a/test/report/Generate/RetriesTest.php +++ /dev/null @@ -1,92 +0,0 @@ - - */ - private static array $runCounters = []; - - #[DisplayName('Reruns of successful test are reported correctly')] - public function testRerunsOfSuccessfulTest(): void - { - $this->expectNotToPerformAssertions(); - } - - #[DisplayName('Reruns of failed test are reported correctly')] - public function testRerunsOfFailedTest(): void - { - self::assertNotSame(1, $this->getRunIndex(__METHOD__)); - } - - /** - * @dataProvider providerData - */ - #[ - DisplayName('Reruns of test with data provider are reported correctly'), - Description("Parameter `retry` has different value on each run but is excluded and doesn't have effect"), - ] - public function testRerunsOfTestWithDataProvider(string $firstValue, string $secondValue): void - { - Allure::parameter('First argument', $firstValue); - Allure::parameter('Second argument', $secondValue); - Allure::parameter('Run index', (string) $this->getRunIndex(__METHOD__), true); - $this->expectNotToPerformAssertions(); - } - - /** - * @return iterable - */ - public function providerData(): iterable - { - return [ - 'First dataset' => ['a', 'b'], - 'Second dataset' => ['b', 'b'], - ]; - } - - /** - * @dataProvider providerIndexedData - */ - #[ - DisplayName('Reruns of test with indexed data provider are reported correctly'), - Description("Parameter `retry` has different value on each run but is excluded and doesn't have effect"), - ] - public function testRerunsOfTestWithIndexedDataProvider(string $firstValue, string $secondValue): void - { - Allure::parameter('First argument', $firstValue); - Allure::parameter('Second argument', $secondValue); - Allure::parameter('Run index', (string) $this->getRunIndex(__METHOD__), true); - $this->expectNotToPerformAssertions(); - } - - /** - * @return iterable - */ - public function providerIndexedData(): iterable - { - return [ - ['a', 'b'], - ['b', 'b'], - ]; - } - - private function getRunIndex(string $method): int - { - self::$runCounters[$method] ??= 0; - - return ++self::$runCounters[$method]; - } -} diff --git a/test/unit/AllureAdapterTest.php b/test/unit/AllureAdapterTest.php index 57f7e20..d3a3c29 100644 --- a/test/unit/AllureAdapterTest.php +++ b/test/unit/AllureAdapterTest.php @@ -6,6 +6,8 @@ use Exception; use LogicException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Qameta\Allure\Model\ContainerResult; use Qameta\Allure\Model\Parameter; @@ -18,9 +20,7 @@ use function array_keys; use function array_map; -/** - * @covers \Qameta\Allure\PHPUnit\AllureAdapter - */ +#[CoversClass(AllureAdapter::class)] class AllureAdapterTest extends TestCase { public function setUp(): void @@ -203,8 +203,8 @@ class: null, * @param string|null $secondMethod * @param array $secondParameters * @param int $expectedRunIndex - * @dataProvider providerRegisterRunRunIndex */ + #[DataProvider('providerRegisterRunRunIndex')] public function testRegisterRun_TestRegisteredBefore_ResultHasMatchingRunIndex( string $firstTest, ?string $firstClass, @@ -255,7 +255,7 @@ class: $secondClass, * int * }> */ - public function providerRegisterRunRunIndex(): iterable + public static function providerRegisterRunRunIndex(): iterable { return [ 'Same test and no parameters' => [ @@ -328,8 +328,8 @@ public function providerRegisterRunRunIndex(): iterable * @param array $secondParameters * @param string $secondUuid * @param string|null $expectedRerunOf - * @dataProvider providerRegisterRunRerunOf */ + #[DataProvider('providerRegisterRunRerunOf')] public function testRegisterRun_TestRegisteredBefore_ResultHasMatchingRerunOf( string $firstTest, ?string $firstClass, @@ -384,7 +384,7 @@ class: $secondClass, * string|null * }> */ - public function providerRegisterRunRerunOf(): iterable + public static function providerRegisterRunRerunOf(): iterable { return [ 'Same test and no parameters' => [ @@ -466,8 +466,8 @@ public function providerRegisterRunRerunOf(): iterable * @param string|null $secondMethod * @param array $secondParameters * @param string $secondUuid - * @dataProvider providerRegisterRunSameTestCaseId */ + #[DataProvider('providerRegisterRunSameTestCaseId')] public function testRegisterRun_MatchingTestRegisteredWithGivenTestCaseId_ResultHasSameTestCaseId( string $firstTest, ?string $firstClass, @@ -520,7 +520,7 @@ class: $secondClass, * string * }> */ - public function providerRegisterRunSameTestCaseId(): iterable + public static function providerRegisterRunSameTestCaseId(): iterable { return [ 'Same test and no parameters' => [ @@ -585,8 +585,8 @@ public function providerRegisterRunSameTestCaseId(): iterable * @param string|null $secondMethod * @param array $secondParameters * @param string $secondUuid - * @dataProvider providerRegisterRunNewTestCaseId */ + #[DataProvider('providerRegisterRunNewTestCaseId')] public function testRegisterRun_NonMatchingTestRegisteredWithGivenTestCaseId_ResultHasNewTestCaseId( string $firstTest, ?string $firstClass, @@ -639,7 +639,7 @@ class: $secondClass, * string * }> */ - public function providerRegisterRunNewTestCaseId(): iterable + public static function providerRegisterRunNewTestCaseId(): iterable { return [ 'Same test and different parameter names' => [ diff --git a/test/unit/AllureExtensionTest.php b/test/unit/AllureExtensionTest.php deleted file mode 100644 index 36294cc..0000000 --- a/test/unit/AllureExtensionTest.php +++ /dev/null @@ -1,261 +0,0 @@ -createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->id('reset') - ->after('switch') - ->method('reset') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('reset') - ->method('create'); - - $extension->executeBeforeTest('b'); - } - - public function testExecuteBeforeTest_Constructed_UpdatesInfoAndStartsCreatedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - $testLifecycle - ->method('switchTo') - ->willReturnSelf(); - $testLifecycle - ->method('reset') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->id('create') - ->method('create') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->id('update') - ->after('create') - ->method('updateInfo') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('update') - ->method('start'); - - $extension->executeBeforeTest('b'); - } - - public function testExecuteAfterTest_Constructed_StopsTestAfterSwitchingContext(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('stop'); - $extension->executeAfterTest('b', 1.2); - } - - public function testExecuteAfterTest_Constructed_UpdatesRunForStoppedTestAndWritesIt(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->method('switchTo') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->id('stop') - ->method('stop') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->id('update') - ->after('stop') - ->method('updateRunInfo') - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('update') - ->method('write'); - $extension->executeAfterTest('b', 1.2); - } - - public function testExecuteAfterTestFailure_Constructed_SetsDetectedOrFailedStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateDetectedStatus') - ->with( - self::identicalTo('c'), - self::identicalTo(Status::failed()), - self::identicalTo(Status::failed()), - ); - $extension->executeAfterTestFailure('b', 'c', 1.2); - } - - - public function testExecuteAfterTestError_Constructed_SetsDetectedOrFailedStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateDetectedStatus') - ->with( - self::identicalTo('c'), - self::identicalTo(Status::broken()), - self::identicalTo(null), - ); - $extension->executeAfterTestError('b', 'c', 1.2); - } - - public function testExecuteAfterIncompleteTest_Constructed_SetsBrokenStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateStatus') - ->with(self::identicalTo('c'), self::identicalTo(Status::broken())); - $extension->executeAfterIncompleteTest('b', 'c', 1.2); - } - - public function testExecuteAfterSkippedTest_Constructed_SetsSkippedStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateStatus') - ->with(self::identicalTo('c'), self::identicalTo(Status::skipped())); - $extension->executeAfterSkippedTest('b', 'c', 1.2); - } - - public function testExecuteAfterTestWarning_Constructed_SetsBrokenStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateStatus') - ->with(self::identicalTo('c'), self::identicalTo(Status::broken())); - $extension->executeAfterTestWarning('b', 'c', 1.2); - } - - public function testExecuteAfterRiskyTest_Constructed_SetsFailedStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateStatus') - ->with(self::identicalTo('c'), self::identicalTo(Status::failed())); - $extension->executeAfterRiskyTest('b', 'c', 1.2); - } - - public function testExecuteAfterSuccessfulTest_Constructed_SetsPassedStatusForSwitchedTest(): void - { - $testLifecycle = $this->createMock(TestLifecycleInterface::class); - $extension = new AllureExtension($testLifecycle); - - $testLifecycle - ->expects(self::once()) - ->id('switch') - ->method('switchTo') - ->with(self::identicalTo('b')) - ->willReturnSelf(); - $testLifecycle - ->expects(self::once()) - ->after('switch') - ->method('updateStatus') - ->with(self::identicalTo(null), self::identicalTo(Status::passed())); - $extension->executeAfterSuccessfulTest('b', 1.2); - } -} diff --git a/test/unit/Event/EventTestTrait.php b/test/unit/Event/EventTestTrait.php new file mode 100644 index 0000000..e1bc2a0 --- /dev/null +++ b/test/unit/Event/EventTestTrait.php @@ -0,0 +1,266 @@ + $line + * @psalm-suppress InternalClass + * @psalm-suppress InternalMethod + */ + return new TestMethod( + $class, + $methodName, + $file, + $line, + $testDox, + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } + + protected function createThrowable( + ?string $message = null, + ?string $description = null, + ): Throwable { + $throwable = new Exception($message ?? 'message'); + + /** + * @var Throwable + * @psalm-suppress InaccessibleMethod + */ + return method_exists(Throwable::class, 'from') + ? Throwable::from($throwable) // early PHPUnit 10 + : new Throwable( + $throwable::class, + $throwable->getMessage(), + $description ?? 'description', + $throwable->getTraceAsString(), + null, + ); + } + + protected function createTestConsideredRiskyEvent( + Test $test, + ?string $message = null, + ): ConsideredRisky { + $message ??= 'message'; + + /** @var non-empty-string $message */ + return new ConsideredRisky( + $this->createTelemetryInfo(), + $test, + $message, + ); + } + + protected function createTestErroredEvent( + Test $test, + ?string $message = null, + ): Errored { + return new Errored( + $this->createTelemetryInfo(), + $test, + $this->createThrowable( + message: $message ?? 'message', + ), + ); + } + + protected function createTestFailedEvent( + Test $test, + ?string $message = null, + ): Failed { + return new Failed( + $this->createTelemetryInfo(), + $test, + $this->createThrowable( + message: $message ?? 'message', + ), + null, + ); + } + + protected function createTestFinishedEvent( + Test $test, + ): Finished { + return new Finished( + $this->createTelemetryInfo(), + $test, + 0, + ); + } + + protected function createTestMarkedIncompleteEvent( + Test $test, + ?string $message = null, + ): MarkedIncomplete { + return new MarkedIncomplete( + $this->createTelemetryInfo(), + $test, + $this->createThrowable( + message: $message ?? 'message', + ), + ); + } + + protected function createTestPassesEvent( + Test $test, + ): Passed { + return new Passed( + $this->createTelemetryInfo(), + $test, + ); + } + + protected function createTestPreparationStartedEvent( + Test $test, + ): PreparationStarted { + return new PreparationStarted( + $this->createTelemetryInfo(), + $test, + ); + } + + protected function createTestPreparedEvent( + Test $test, + ): Prepared { + return new Prepared( + $this->createTelemetryInfo(), + $test, + ); + } + + protected function createTestSkippedEvent( + Test $test, + ?string $message = null, + ): Skipped { + return new Skipped( + $this->createTelemetryInfo(), + $test, + $message ?? 'message', + ); + } + + protected function createTestWarningTriggeredEvent( + Test $test, + ?string $message = null, + ): WarningTriggered { + $message ??= 'message'; + + /** + * @var non-empty-string $message + * @psalm-suppress TooManyArguments + */ + return new WarningTriggered( + $this->createTelemetryInfo(), + $test, + $message, + 'file', + 1, + false, + ); + } +} diff --git a/test/unit/Event/TestConsideredRiskySubscriberTest.php b/test/unit/Event/TestConsideredRiskySubscriberTest.php new file mode 100644 index 0000000..27e0722 --- /dev/null +++ b/test/unit/Event/TestConsideredRiskySubscriberTest.php @@ -0,0 +1,58 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestConsideredRiskySubscriber($testLifecycle); + $event = $this->createTestConsideredRiskyEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesStatusAsFailedForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestConsideredRiskySubscriber($testLifecycle); + $event = $this->createTestConsideredRiskyEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + message: 'c', + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateStatus') + ->with( + self::identicalTo('c'), + self::identicalTo(Status::failed()), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestErroredSubscriberTest.php b/test/unit/Event/TestErroredSubscriberTest.php new file mode 100644 index 0000000..bfa2146 --- /dev/null +++ b/test/unit/Event/TestErroredSubscriberTest.php @@ -0,0 +1,59 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestErroredSubscriber($testLifecycle); + $event = $this->createTestErroredEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesDetectedStatusAsBrokenForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestErroredSubscriber($testLifecycle); + $event = $this->createTestErroredEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + message: 'c', + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateDetectedStatus') + ->with( + self::identicalTo('c'), + self::identicalTo(Status::broken()), + self::identicalTo(null), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestFailedSubscriberTest.php b/test/unit/Event/TestFailedSubscriberTest.php new file mode 100644 index 0000000..4bd6a3b --- /dev/null +++ b/test/unit/Event/TestFailedSubscriberTest.php @@ -0,0 +1,59 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestFailedSubscriber($testLifecycle); + $event = $this->createTestFailedEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesDetectedStatusAsFailedForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestFailedSubscriber($testLifecycle); + $event = $this->createTestFailedEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + message: 'c', + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateDetectedStatus') + ->with( + self::identicalTo('c'), + self::identicalTo(Status::failed()), + self::identicalTo(Status::failed()), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestFinishedSubscriberTest.php b/test/unit/Event/TestFinishedSubscriberTest.php new file mode 100644 index 0000000..3ffcc91 --- /dev/null +++ b/test/unit/Event/TestFinishedSubscriberTest.php @@ -0,0 +1,64 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestFinishedSubscriber($testLifecycle); + $event = $this->createTestFinishedEvent( + $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_WritesUpdatedStoppedTestAfterSwitchingContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestFinishedSubscriber($testLifecycle); + $event = $this->createTestFinishedEvent( + $this->createTestMethod(class: 'a', methodName: 'b'), + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->id('stop') + ->after('switch') + ->method('stop') + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->id('update') + ->after('stop') + ->method('updateRunInfo') + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('update') + ->method('write'); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestMarkedIncompleteSubscriberTest.php b/test/unit/Event/TestMarkedIncompleteSubscriberTest.php new file mode 100644 index 0000000..8ca2124 --- /dev/null +++ b/test/unit/Event/TestMarkedIncompleteSubscriberTest.php @@ -0,0 +1,58 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestMarkedIncompleteSubscriber($testLifecycle); + $event = $this->createTestMarkedIncompleteEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesStatusAsBrokenForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestMarkedIncompleteSubscriber($testLifecycle); + $event = $this->createTestMarkedIncompleteEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + message: 'c', + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateStatus') + ->with( + self::identicalTo('c'), + self::identicalTo(Status::broken()), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestPassedSubscriberTest.php b/test/unit/Event/TestPassedSubscriberTest.php new file mode 100644 index 0000000..5504100 --- /dev/null +++ b/test/unit/Event/TestPassedSubscriberTest.php @@ -0,0 +1,57 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestPassedSubscriber($testLifecycle); + $event = $this->createTestPassesEvent( + $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesStatusAsPassedForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestPassedSubscriber($testLifecycle); + $event = $this->createTestPassesEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateStatus') + ->with( + self::identicalTo(null), + self::identicalTo(Status::passed()), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestPreparationStartedSubscriberTest.php b/test/unit/Event/TestPreparationStartedSubscriberTest.php new file mode 100644 index 0000000..41ccb79 --- /dev/null +++ b/test/unit/Event/TestPreparationStartedSubscriberTest.php @@ -0,0 +1,58 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestPreparationStartedSubscriber($testLifecycle); + $event = $this->createTestPreparationStartedEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_CreatesTestAfterResettingSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestPreparationStartedSubscriber($testLifecycle); + $event = $this->createTestPreparationStartedEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->id('reset') + ->after('switch') + ->method('reset') + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('reset') + ->method('create'); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestPreparedSubscriberTest.php b/test/unit/Event/TestPreparedSubscriberTest.php new file mode 100644 index 0000000..14a86a3 --- /dev/null +++ b/test/unit/Event/TestPreparedSubscriberTest.php @@ -0,0 +1,58 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestPreparedSubscriber($testLifecycle); + $event = $this->createTestPreparedEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_StartsTestsWithUpdatedInfoInSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestPreparedSubscriber($testLifecycle); + $event = $this->createTestPreparedEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->id('update') + ->after('switch') + ->method('updateInfo') + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('update') + ->method('start'); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestSkippedSubscriberTest.php b/test/unit/Event/TestSkippedSubscriberTest.php new file mode 100644 index 0000000..66f8d2a --- /dev/null +++ b/test/unit/Event/TestSkippedSubscriberTest.php @@ -0,0 +1,58 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestSkippedSubscriber($testLifecycle); + $event = $this->createTestSkippedEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesStatusAsSkippedForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestSkippedSubscriber($testLifecycle); + $event = $this->createTestSkippedEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + message: 'c', + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateStatus') + ->with( + self::identicalTo('c'), + self::identicalTo(Status::skipped()), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/Event/TestWarningTriggeredSubscriberTest.php b/test/unit/Event/TestWarningTriggeredSubscriberTest.php new file mode 100644 index 0000000..3fad07a --- /dev/null +++ b/test/unit/Event/TestWarningTriggeredSubscriberTest.php @@ -0,0 +1,58 @@ +createMock(TestLifecycleInterface::class); + $subscriber = new TestWarningTriggeredSubscriber($testLifecycle); + $event = $this->createTestWarningTriggeredEvent( + test: $this->createStub(Test::class), + ); + + $testLifecycle + ->expects(self::never()) + ->method('switchTo'); + $subscriber->notify($event); + } + + public function testNotify_ValidTestMethod_UpdatesStatusAsBrokenForSwitchedContext(): void + { + $testLifecycle = $this->createMock(TestLifecycleInterface::class); + $subscriber = new TestWarningTriggeredSubscriber($testLifecycle); + $event = $this->createTestWarningTriggeredEvent( + test: $this->createTestMethod(class: 'a', methodName: 'b'), + message: 'c', + ); + + $testLifecycle + ->expects(self::once()) + ->id('switch') + ->method('switchTo') + ->with(self::identicalTo('a::b')) + ->willReturnSelf(); + $testLifecycle + ->expects(self::once()) + ->after('switch') + ->method('updateStatus') + ->with( + self::identicalTo('c'), + self::identicalTo(Status::broken()), + ); + $subscriber->notify($event); + } +} diff --git a/test/unit/ExceptionDetailsTraitTest.php b/test/unit/ExceptionDetailsTraitTest.php index 7da9569..91c2b4a 100644 --- a/test/unit/ExceptionDetailsTraitTest.php +++ b/test/unit/ExceptionDetailsTraitTest.php @@ -5,15 +5,14 @@ namespace Qameta\Allure\PHPUnit\Test\Unit; use Exception; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Qameta\Allure\PHPUnit\ExceptionDetailsTrait; use Qameta\Allure\PHPUnit\AllureAdapter; use Qameta\Allure\PHPUnit\AllureAdapterInterface; use Throwable; -/** - * @covers \Qameta\Allure\PHPUnit\ExceptionDetailsTrait - */ +#[CoversClass(ExceptionDetailsTrait::class)] class ExceptionDetailsTraitTest extends TestCase { public function testOnNotSuccessfulTest_GivenException_ThrowsSameException(): void diff --git a/test/unit/Internal/ConfigTest.php b/test/unit/Internal/ConfigTest.php index 07d8e1b..46a9a24 100644 --- a/test/unit/Internal/ConfigTest.php +++ b/test/unit/Internal/ConfigTest.php @@ -4,6 +4,8 @@ namespace Qameta\Allure\PHPUnit\Test\Unit\Internal; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Qameta\Allure\Hook\LifecycleHookInterface; use Qameta\Allure\PHPUnit\Internal\Config; @@ -13,14 +15,10 @@ use RuntimeException; use stdClass; -/** - * @covers \Qameta\Allure\PHPUnit\Internal\Config - */ +#[CoversClass(Config::class)] class ConfigTest extends TestCase { - /** - * @dataProvider providerNoOutputDirectory - */ + #[DataProvider('providerNoOutputDirectory')] public function testGetOutputDirectory_EmptyData_ReturnsNull(array $data): void { $config = new Config($data); @@ -30,7 +28,7 @@ public function testGetOutputDirectory_EmptyData_ReturnsNull(array $data): void /** * @return iterable */ - public function providerNoOutputDirectory(): iterable + public static function providerNoOutputDirectory(): iterable { return [ 'No entry' => [[]], @@ -52,9 +50,7 @@ public function testGetOutputDirectory_InvalidData_ThrowsException(): void $config->getOutputDirectory(); } - /** - * @dataProvider providerNoLinkTemplates - */ + #[DataProvider('providerNoLinkTemplates')] public function testGetLinkTemplates_EmptyData_ReturnsEmptyList(array $data): void { $config = new Config($data); @@ -64,7 +60,7 @@ public function testGetLinkTemplates_EmptyData_ReturnsEmptyList(array $data): vo /** * @return iterable */ - public function providerNoLinkTemplates(): iterable + public static function providerNoLinkTemplates(): iterable { return [ 'No entry' => [[]], @@ -152,9 +148,7 @@ public function testGetLinkTemplates_ValidClassNameInData_ReturnsObjectOfSameCla self::assertEquals($expectedData, $config->getLinkTemplates()); } - /** - * @dataProvider providerNoSetupHook - */ + #[DataProvider('providerNoSetupHook')] public function testGetSetupHook_EmptyData_ReturnsNull(array $data): void { $config = new Config($data); @@ -164,7 +158,7 @@ public function testGetSetupHook_EmptyData_ReturnsNull(array $data): void /** * @return iterable */ - public function providerNoSetupHook(): iterable + public static function providerNoSetupHook(): iterable { return [ 'No entry' => [[]], @@ -172,9 +166,7 @@ public function providerNoSetupHook(): iterable ]; } - /** - * @dataProvider providerInvalidSetupHook - */ + #[DataProvider('providerInvalidSetupHook')] public function testGetSetupHook_InvalidTypeInData_ThrowsException(array $data): void { $config = new Config($data); @@ -186,7 +178,7 @@ public function testGetSetupHook_InvalidTypeInData_ThrowsException(array $data): /** * @return iterable */ - public function providerInvalidSetupHook(): iterable + public static function providerInvalidSetupHook(): iterable { return [ 'Invalid type' => [['setupHook' => 1]], @@ -207,9 +199,7 @@ public function testGetSetupHook_CallableClassInData_ReturnsInstanceOfSameClass( self::assertInstanceOf(OnSetupHook::class, $config->getSetupHook()); } - /** - * @dataProvider providerNoThreadDetector - */ + #[DataProvider('providerNoThreadDetector')] public function testGetThreadDetector_EmptyData_ReturnsNull(array $data): void { $config = new Config($data); @@ -219,7 +209,7 @@ public function testGetThreadDetector_EmptyData_ReturnsNull(array $data): void /** * @return iterable */ - public function providerNoThreadDetector(): iterable + public static function providerNoThreadDetector(): iterable { return [ 'No entry' => [[]], @@ -269,9 +259,7 @@ public function testGetThreadDetector_ValidClassInData_ReturnsInstanceOfSameClas self::assertInstanceOf(TestThreadDetector::class, $config->getThreadDetector()); } - /** - * @dataProvider providerNoLifecycleHooks - */ + #[DataProvider('providerNoLifecycleHooks')] public function testGetLifecycleHooks_EmptyData_ReturnsEmptyList(array $data): void { $config = new Config($data); @@ -281,7 +269,7 @@ public function testGetLifecycleHooks_EmptyData_ReturnsEmptyList(array $data): v /** * @return iterable */ - public function providerNoLifecycleHooks(): iterable + public static function providerNoLifecycleHooks(): iterable { return [ 'No entry' => [[]], diff --git a/test/unit/Internal/DefaultThreadDetectorTest.php b/test/unit/Internal/DefaultThreadDetectorTest.php index 1dabf70..51288a5 100644 --- a/test/unit/Internal/DefaultThreadDetectorTest.php +++ b/test/unit/Internal/DefaultThreadDetectorTest.php @@ -4,12 +4,11 @@ namespace Qameta\Allure\PHPUnit\Test\Unit\Internal; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Qameta\Allure\PHPUnit\Internal\DefaultThreadDetector; -/** - * @covers \Qameta\Allure\PHPUnit\Internal\DefaultThreadDetector - */ +#[CoversClass(DefaultThreadDetector::class)] class DefaultThreadDetectorTest extends TestCase { public function testGetThread_WithoutParatestToken_ReturnsNull(): void diff --git a/test/unit/Internal/TestInfoTest.php b/test/unit/Internal/TestInfoTest.php index d4129f2..bea6eb0 100644 --- a/test/unit/Internal/TestInfoTest.php +++ b/test/unit/Internal/TestInfoTest.php @@ -4,13 +4,13 @@ namespace Qameta\Allure\PHPUnit\Test\Unit\Internal; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Qameta\Allure\PHPUnit\Internal\TestInfo; use stdClass; -/** - * @covers \Qameta\Allure\PHPUnit\Internal\TestInfo - */ +#[CoversClass(TestInfo::class)] class TestInfoTest extends TestCase { public function testGetTest_ConstructedWithTest_ReturnsSameValue(): void @@ -28,8 +28,8 @@ class: null, /** * @param class-string|null $class - * @dataProvider providerGetClass */ + #[DataProvider('providerGetClass')] public function testGetClass_ConstructedWithClass_ReturnsSameClass(?string $class): void { $info = new TestInfo( @@ -46,7 +46,7 @@ class: $class, /** * @return iterable */ - public function providerGetClass(): iterable + public static function providerGetClass(): iterable { return [ 'Null' => [null], @@ -54,9 +54,7 @@ public function providerGetClass(): iterable ]; } - /** - * @dataProvider providerNullableString - */ + #[DataProvider('providerNullableString')] public function testGetMethod_ConstructedWithMethod_ReturnsSameMethod(?string $method): void { $info = new TestInfo( @@ -73,7 +71,7 @@ class: null, /** * @return iterable */ - public function providerNullableString(): iterable + public static function providerNullableString(): iterable { return [ 'Null' => [null], @@ -81,9 +79,7 @@ public function providerNullableString(): iterable ]; } - /** - * @dataProvider providerNullableString - */ + #[DataProvider('providerNullableString')] public function testGetDataLabel_ConstructedWithDataLabel_ReturnsSameLabel(?string $dataLabel): void { $info = new TestInfo( @@ -97,9 +93,7 @@ class: null, self::assertSame($dataLabel, $info->getDataLabel()); } - /** - * @dataProvider providerNullableString - */ + #[DataProvider('providerNullableString')] public function testGetHost_ConstructedWithHost_ReturnsSameHost(?string $host): void { $info = new TestInfo( @@ -113,9 +107,7 @@ class: null, self::assertSame($host, $info->getHost()); } - /** - * @dataProvider providerNullableString - */ + #[DataProvider('providerNullableString')] public function testGetThread_ConstructedWithThread_ReturnsSameThread(?string $thread): void { $info = new TestInfo( @@ -133,8 +125,8 @@ class: null, * @param class-string|null $class * @param string|null $method * @param string|null $expectedFullName - * @dataProvider providerGetFullName */ + #[DataProvider('providerGetFullName')] public function testGetFullName_ConstructedWithGivenClassAndMethod_ReturnsMatchingValue( ?string $class, ?string $method, @@ -154,7 +146,7 @@ class: $class, /** * @return iterable */ - public function providerGetFullName(): iterable + public static function providerGetFullName(): iterable { return [ 'Both class and method are null' => [null, null, null], @@ -169,8 +161,8 @@ public function providerGetFullName(): iterable * @param class-string|null $class * @param string|null $method * @param string $expectedName - * @dataProvider providerGetName */ + #[DataProvider('providerGetName')] public function testGetName_Constructed_ReturnsMatchingTest( string $test, ?string $class, @@ -191,7 +183,7 @@ class: $class, /** * @return iterable */ - public function providerGetName(): iterable + public static function providerGetName(): iterable { return [ 'Class is not set' => ['a', null, 'b', 'a'], diff --git a/test/unit/Internal/TestRunInfoTest.php b/test/unit/Internal/TestRunInfoTest.php index a67870e..2cf1d75 100644 --- a/test/unit/Internal/TestRunInfoTest.php +++ b/test/unit/Internal/TestRunInfoTest.php @@ -4,13 +4,13 @@ namespace Qameta\Allure\PHPUnit\Test\Unit\Internal; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Qameta\Allure\PHPUnit\Internal\TestInfo; use Qameta\Allure\PHPUnit\Internal\TestRunInfo; -/** - * @covers \Qameta\Allure\PHPUnit\Internal\TestRunInfo - */ +#[CoversClass(TestRunInfo::class)] class TestRunInfoTest extends TestCase { public function testGetTestInfo_ConstructedWithTestInfo_ReturnsSameInstance(): void @@ -57,8 +57,8 @@ class: null, /** * @param string|null $rerunOf - * @dataProvider providerRerunOf */ + #[DataProvider('providerRerunOf')] public function testGetRerunOf_ConstructedWithRerunOf_ReturnsSameRerunOf(?string $rerunOf): void { $testInfo = new TestInfo( @@ -83,7 +83,7 @@ class: null, /** * @return iterable */ - public function providerRerunOf(): iterable + public static function providerRerunOf(): iterable { return [ 'Null' => [null], diff --git a/test/unit/Internal/TestStartInfoTest.php b/test/unit/Internal/TestStartInfoTest.php index c55f99f..662653d 100644 --- a/test/unit/Internal/TestStartInfoTest.php +++ b/test/unit/Internal/TestStartInfoTest.php @@ -4,12 +4,11 @@ namespace Qameta\Allure\PHPUnit\Test\Unit\Internal; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Qameta\Allure\PHPUnit\Internal\TestStartInfo; -/** - * @covers \Qameta\Allure\PHPUnit\Internal\TestStartInfo - */ +#[CoversClass(TestStartInfo::class)] class TestStartInfoTest extends TestCase { public function testGetContainerId_ConstructedWithContainerId_ReturnsSameId(): void