Skip to content

Commit

Permalink
allowed skipping a test if a Composer package is not installed (in a …
Browse files Browse the repository at this point in the history
…version)

this closes #60
  • Loading branch information
konecnyjakub committed Jan 1, 2025
1 parent e8e199f commit ecdf242
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 17 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Version 8.0.0-dev
- added assertions assertFileExists, assertFileNotExists, assertDirectoryExists and assertDirectoryNotExists
- allowed using attribute RequiresPhpExtension multiple times on one test method
- BC break: used term test suite instead of test case whenever possible (events TestCaseStarted and TestCaseFinished renamed to TestSuiteStarted and TestSuiteFinished respectively, exception InvalidTestCaseException to InvalidTestSuiteException, some class properties too)
- allowed skipping a test if a Composer package is not installed (in a version)

Version 7.3.1
- allowed installation konecnyjakub/event-dispatcher 2
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,24 +198,26 @@ final class Tests extends MyTester\TestCase
}
```

. You can also add conditions when the test should be skipped. For that you need to use a specific attribute. One supported is RequiresPhpVersion. If your version of PHP is lesser than its value, the test is skipped. You can also use attribute RequiresPhpExtension where the test will be skipped when that extension is not loaded. If you use attribute RequiresSapi, the test will not be executed if the current sapi is different. With attribute RequiresOsFamily, you can skip a test if tests are run on a different OS family (taken from constant PHP_OS_FAMILY). Skipped tests are shown in output. Examples:
. You can also add conditions when the test should be skipped. For that you need to use a specific attribute. One supported is RequiresPhpVersion, if your version of PHP is lesser than its value, the test is skipped. You can also use attribute RequiresPhpExtension where the test will be skipped when that extension is not loaded. If you use attribute RequiresSapi, the test will not be executed if the current sapi is different. With attribute RequiresOsFamily, you can skip a test if tests are run on a different OS family (taken from constant PHP_OS_FAMILY). With attribute RequiresPackage you can skip a test if a Composer package is not installed; if you have installed package composer/semver, you can also pass a version constraint as second parameter. Skipped tests are shown in output. Examples:

```php
<?php
declare(strict_types=1);

use MyTester\Attributes\Skip;
use MyTester\Attributes\RequiresOsFamily;
use MyTester\Attributes\RequiresPackage;
use MyTester\Attributes\RequiresPhpVersion;
use MyTester\Attributes\RequiresPhpExtension;
use MyTester\Attributes\RequiresSapi;
use MyTester\Attributes\RequiresOsFamily;

final class Tests extends MyTester\TestCase
{
#[RequiresPhpVersion("5.4.1")]
#[RequiresPhpExtension("abc")]
#[RequiresSapi("cgi")]
#[RequiresOsFamily("Solaris")]
#[RequiresPackage("phpstan/phpstan")]
public function testTestName(): void
{
$this->assertTrue(false);
Expand Down
2 changes: 1 addition & 1 deletion RELEASE_NOTES
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Automated tests runner can now print list of active extensions along My Tester a

It adds new assertions assertFileExists, assertFileNotExists, assertDirectoryExists and assertDirectoryNotExists.

Attribute RequiresPhpExtension can be used multiple times on one method.
Attribute RequiresPhpExtension can be used multiple times on one method. It is possible to skip a test if a Composer package is not installed (in a version)

Term test suite is now used at a lot of places instead of test case, this causes quite a few BC breaks.

Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"nette/robot-loader": "^4.0.3",
"nette/bootstrap": "^3.2.4",
"nette/application": "^3.2",
"composer/semver": "^3.0",
"php-parallel-lint/php-parallel-lint": "^1.4",
"php-parallel-lint/php-console-highlighter": "^0.5",
"squizlabs/php_codesniffer": "^3.11",
Expand All @@ -38,12 +39,14 @@
"suggest": {
"ext-pcov": "For generating code coverage reports",
"ext-dom": "For generating Cobertura code coverage reports and/or JUnit reports",
"ext-xdebug": "Alternative engine for generating code coverage reports"
"ext-xdebug": "Alternative engine for generating code coverage reports",
"composer/semver": "To skip a test method based on package version"
},
"conflict": {
"nette/robot-loader": "<4.0.3",
"nette/di": "<3.2",
"nette/application": "<3.2"
"nette/application": "<3.2",
"composer/semver": "<3.0"
},
"autoload": {
"psr-4": {
Expand Down
1 change: 1 addition & 0 deletions src/AnnotationsSkipChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ final class AnnotationsSkipChecker implements ISkipChecker
"requiresPhpExtension" => Attributes\RequiresPhpExtension::class,
"requiresSapi" => Attributes\RequiresSapi::class,
"requiresOsFamily" => Attributes\RequiresOsFamily::class,
"requiresPackage" => Attributes\RequiresPackage::class,
];

public function __construct(private readonly Reader $annotationsReader)
Expand Down
48 changes: 48 additions & 0 deletions src/Attributes/RequiresPackage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);

namespace MyTester\Attributes;

use Attribute;
use Composer\InstalledVersions;
use Composer\Semver\VersionParser;
use MyTester\ISkipAttribute;

/**
* Requires package attribute
* Defines a Composer package required for a test
*
* @author Jakub Konečný
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
final readonly class RequiresPackage implements ISkipAttribute
{
public function __construct(public string $packageName, public ?string $version = null)
{
if ($this->version !== null && !InstalledVersions::isInstalled("composer/semver")) {
trigger_error(
"Specifying a version constraint for package requires package composer/semver",
E_USER_ERROR
);
}
}

public function getSkipValue(): ?string
{
if (!InstalledVersions::isInstalled($this->packageName)) {
return "package $this->packageName is not installed";
}
if (
$this->version !== null &&
!InstalledVersions::satisfies(new VersionParser(), $this->packageName, $this->version)
) {
return "package $this->packageName is not installed in version $this->version";
}
return null;
}

public function getValue(): string
{
return $this->packageName . (is_string($this->version) ? " $this->version" : "");
}
}
30 changes: 30 additions & 0 deletions tests/Attributes/RequiresPackageTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

namespace MyTester\Attributes;

use MyTester\TestCase;

/**
* Test suite for class RequiresPackage
*
* @author Jakub Konečný
*/
#[TestSuite("RequiresPackage")]
final class RequiresPackageTest extends TestCase
{
public function testGetSkipValue(): void
{
$attribute = new RequiresPackage("composer/semver");
$this->assertNull($attribute->getSkipValue());

$attribute = new RequiresPackage("composer/semver", "^3.0");
$this->assertNull($attribute->getSkipValue());

$attribute = new RequiresPackage("phpunit/phpunit");
$this->assertSame("package phpunit/phpunit is not installed", $attribute->getSkipValue());

$attribute = new RequiresPackage("phpstan/phpstan", "^1.0");
$this->assertSame("package phpstan/phpstan is not installed in version ^1.0", $attribute->getSkipValue());
}
}
2 changes: 1 addition & 1 deletion tests/Bridges/NetteRobotLoader/TestSuitesFinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ public function testGetSuites(): void
{
$testSuitesFinder = new TestSuitesFinder();
$suites = $testSuitesFinder->getSuites(__DIR__ . "/../../");
$this->assertCount(37, $suites);
$this->assertCount(38, $suites);
}
}
2 changes: 1 addition & 1 deletion tests/ComposerTestSuitesFinderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ public function testGetSuites(): void
{
$testSuitesFinder = new ComposerTestSuitesFinder();
$suites = $testSuitesFinder->getSuites(__DIR__);
$this->assertCount(37, $suites);
$this->assertCount(38, $suites);
}
}
41 changes: 31 additions & 10 deletions tests/TestCaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use MyTester\Attributes\IgnoreDeprecations;
use MyTester\Attributes\NoAssertions;
use MyTester\Attributes\RequiresOsFamily;
use MyTester\Attributes\RequiresPackage;
use MyTester\Attributes\RequiresPhpExtension;
use MyTester\Attributes\RequiresPhpVersion;
use MyTester\Attributes\RequiresSapi;
Expand Down Expand Up @@ -178,6 +179,16 @@ public function testSkipOsFamily(): void
$this->assertTrue(false);
}

/**
* Test skipping based on installed package
*/
#[Test("Package")]
#[RequiresPackage("phpstan/phpstan", "^1.0")]
public function testSkipPackage(): void
{
$this->assertTrue(false);
}

#[Test("No assertions")]
#[NoAssertions]
public function testNoAssertions(): void
Expand Down Expand Up @@ -235,6 +246,7 @@ public function testGetTestMethodsNames(): void
"testCgiSapi",
"testSkipExtension",
"testSkipOsFamily",
"testSkipPackage",
"testNoAssertions",
"testDeprecation",
"testGetSuiteName",
Expand All @@ -259,7 +271,7 @@ public function testShouldReportDeprecations(): void
public function testGetJobs(): void
{
$jobs = $this->getJobs();
$this->assertCount(29, $jobs);
$this->assertCount(30, $jobs);

$job = $jobs[0];
$this->assertSame("TestCase::testState", $job->name);
Expand Down Expand Up @@ -433,6 +445,15 @@ public function testGetJobs(): void
$this->assertTrue($job->reportDeprecations);

$job = $jobs[19];
$this->assertSame("Package", $job->name);
$this->assertSame([$this, "testSkipPackage", ], $job->callback);
$this->assertSame([], $job->params);
$this->assertTrue((bool) $job->skip);
$this->assertCount(1, $job->onAfterExecute);
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[20];
$this->assertSame("No assertions", $job->name);
$this->assertSame([$this, "testNoAssertions", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -441,7 +462,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[20];
$job = $jobs[21];
$this->assertSame("Deprecation", $job->name);
$this->assertSame([$this, "testDeprecation", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -454,7 +475,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertFalse($job->reportDeprecations);

$job = $jobs[21];
$job = $jobs[22];
$this->assertSame("TestCase::testGetSuiteName", $job->name);
$this->assertSame([$this, "testGetSuiteName", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -463,7 +484,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[22];
$job = $jobs[23];
$this->assertSame("TestCase::testGetJobName", $job->name);
$this->assertSame([$this, "testGetJobName", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -472,7 +493,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[23];
$job = $jobs[24];
$this->assertSame("TestCase::testGetTestMethodsNames", $job->name);
$this->assertSame([$this, "testGetTestMethodsNames", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -481,7 +502,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[24];
$job = $jobs[25];
$this->assertSame("TestCase::testShouldReportDeprecations", $job->name);
$this->assertSame([$this, "testShouldReportDeprecations", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -490,7 +511,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[25];
$job = $jobs[26];
$this->assertSame("TestCase::testGetJobs", $job->name);
$this->assertSame([$this, "testGetJobs", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -499,7 +520,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[26];
$job = $jobs[27];
$this->assertSame("TestCase::testIncomplete", $job->name);
$this->assertSame([$this, "testIncomplete", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -508,7 +529,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[27];
$job = $jobs[28];
$this->assertSame("TestCase::testSkipInside", $job->name);
$this->assertSame([$this, "testSkipInside", ], $job->callback);
$this->assertSame([], $job->params);
Expand All @@ -517,7 +538,7 @@ public function testGetJobs(): void
$this->assertSame("", $job->dataSetName);
$this->assertTrue($job->reportDeprecations);

$job = $jobs[28];
$job = $jobs[29];
$this->assertSame("TestCase::testWhatever", $job->name);
$this->assertSame([$this, "testWhatever", ], $job->callback);
$this->assertSame([], $job->params);
Expand Down

0 comments on commit ecdf242

Please sign in to comment.