Skip to content

Commit

Permalink
Closes #5201
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianbergmann committed Feb 19, 2023
1 parent e8ce917 commit 9fdc09c
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 6 deletions.
4 changes: 4 additions & 0 deletions ChangeLog-10.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ All notable changes of the PHPUnit 10.1 release series are documented in this fi

## [10.1.0] - 2023-04-07

### Added

* [#5201](https://github.com/sebastianbergmann/phpunit/issues/5201): Add `TestCase::registerFailureInterface()` to register interface that marks exceptions to be treated as failures, not errors

[10.1.0]: https://github.com/sebastianbergmann/phpunit/compare/10.0...main
47 changes: 41 additions & 6 deletions src/Framework/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ abstract class TestCase extends Assert implements Reorderable, SelfDescribing, T
private ?Event\Code\TestMethod $testValueObjectForEvents = null;
private bool $wasPrepared = false;

/**
* @psalm-var list<class-string>
*/
private array $failureInterfaces = [];

/**
* Returns a matcher that matches when the method is executed
* zero or more times.
Expand Down Expand Up @@ -647,13 +652,24 @@ final public function runBare(): void
} catch (TimeoutException $e) {
$this->status = TestStatus::risky($e->getMessage());
} catch (Throwable $_e) {
$e = $_e;
$this->status = TestStatus::error($_e->getMessage());
$e = $_e;

$emitter->testErrored(
$this->valueObjectForEvents(),
Event\Code\Throwable::from($_e)
);
if ($this->isRegisteredFailure($_e)) {
$this->status = TestStatus::failure($_e->getMessage());

$emitter->testFailed(
$this->valueObjectForEvents(),
Event\Code\Throwable::from($_e),
null
);
} else {
$this->status = TestStatus::error($_e->getMessage());

$emitter->testErrored(
$this->valueObjectForEvents(),
Event\Code\Throwable::from($_e)
);
}
}

if ($this->stopOutputBuffering() && !isset($e)) {
Expand Down Expand Up @@ -1004,6 +1020,14 @@ final public function wasPrepared(): bool
return $this->wasPrepared;
}

/**
* @psalm-param class-string $interface
*/
final protected function registerFailureInterface(string $interface): void
{
$this->failureInterfaces[] = $interface;
}

/**
* @throws AssertionFailedError
* @throws Exception
Expand Down Expand Up @@ -2111,4 +2135,15 @@ private function expectedExceptionWasNotRaised(): void
);
}
}

private function isRegisteredFailure(Throwable $t): bool
{
foreach ($this->failureInterfaces as $failureInterface) {
if ($t instanceof $failureInterface) {
return true;
}
}

return false;
}
}
16 changes: 16 additions & 0 deletions tests/end-to-end/event/_files/CustomFailureException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\TestFixture\Event;

use Exception;

final class CustomFailureException extends Exception implements CustomFailureInterface
{
}
14 changes: 14 additions & 0 deletions tests/end-to-end/event/_files/CustomFailureInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\TestFixture\Event;

interface CustomFailureInterface
{
}
27 changes: 27 additions & 0 deletions tests/end-to-end/event/_files/CustomFailureInterfaceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace PHPUnit\TestFixture\Event;

use PHPUnit\Framework\TestCase;

final class CustomFailureInterfaceTest extends TestCase
{
public function testOne(): void
{
$this->registerFailureInterface(CustomFailureInterface::class);

throw new CustomFailureException('this should be treated as a failure');
}

public function testTwo(): void
{
throw new CustomFailureException('this should be treated as an error');
}
}
48 changes: 48 additions & 0 deletions tests/end-to-end/event/test-registered-failure-interface.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
--TEST--
The right events are emitted in the right order for a test that registers a failure interface
--SKIPIF--
<?php declare(strict_types=1);
if (DIRECTORY_SEPARATOR === '\\') {
print "skip: this test does not work on Windows / GitHub Actions\n";
}
--FILE--
<?php declare(strict_types=1);
$traceFile = tempnam(sys_get_temp_dir(), __FILE__);

$_SERVER['argv'][] = '--do-not-cache-result';
$_SERVER['argv'][] = '--no-configuration';
$_SERVER['argv'][] = '--no-output';
$_SERVER['argv'][] = '--log-events-text';
$_SERVER['argv'][] = $traceFile;
$_SERVER['argv'][] = __DIR__ . '/_files/CustomFailureInterfaceTest.php';

require __DIR__ . '/../../bootstrap.php';

(new PHPUnit\TextUI\Application)->run($_SERVER['argv']);

print file_get_contents($traceFile);

unlink($traceFile);
--EXPECTF--
PHPUnit Started (PHPUnit %s using %s)
Test Runner Configured
Test Suite Loaded (2 tests)
Event Facade Sealed
Test Runner Started
Test Suite Sorted
Test Runner Execution Started (2 tests)
Test Suite Started (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest, 2 tests)
Test Preparation Started (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne)
Test Prepared (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne)
Test Failed (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne)
this should be treated as a failure
Test Finished (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne)
Test Preparation Started (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo)
Test Prepared (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo)
Test Errored (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo)
this should be treated as an error
Test Finished (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo)
Test Suite Finished (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest, 2 tests)
Test Runner Execution Finished
Test Runner Finished
PHPUnit Finished (Shell Exit Code: 2)

0 comments on commit 9fdc09c

Please sign in to comment.