Skip to content

Commit c0502c9

Browse files
committed
feat: implement status detection for test failures
- Added `StatusDetector` class to determine the type of test failures (assertion failures vs. other errors). - Updated event subscribers to utilize `StatusDetector` for setting appropriate test statuses. - Introduced unit tests for `StatusDetector` to ensure correct functionality in identifying failure types and statuses. - Updated `composer.json` and `composer.lock` to reflect new dependencies and version changes.
1 parent 41ddefd commit c0502c9

9 files changed

+223
-76
lines changed

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"require": {
2323
"php": "^8.1",
2424
"phpunit/phpunit": "^10 || ^11",
25-
"qase/php-commons": "^2.1.1"
25+
"qase/php-commons": "^2.1.4"
2626
},
2727
"autoload": {
2828
"psr-4": {
@@ -34,7 +34,7 @@
3434
"Tests\\": "tests/"
3535
}
3636
},
37-
"version": "2.1.3",
37+
"version": "2.1.4",
3838
"scripts": {
3939
"test": "phpunit"
4040
},

composer.lock

Lines changed: 81 additions & 69 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Events/TestConsideredRiskySubscriber.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ public function notify(ConsideredRisky $event): void
2828
return;
2929
}
3030

31-
$this->reporter->updateStatus($test, 'failed', $event->message());
31+
$this->reporter->updateStatus($test, 'invalid', $event->message());
3232
}
3333
}

src/Events/TestErroredSubscriber.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPUnit\Event\Test\Errored;
99
use PHPUnit\Event\Test\ErroredSubscriber;
1010
use Qase\PHPUnitReporter\QaseReporterInterface;
11+
use Qase\PHPUnitReporter\StatusDetector;
1112

1213
final class TestErroredSubscriber implements ErroredSubscriber
1314
{
@@ -28,6 +29,9 @@ public function notify(Errored $event): void
2829
return;
2930
}
3031

31-
$this->reporter->updateStatus($test, 'failed', $event->throwable()->message(), $event->throwable()->asString());
32+
$throwable = $event->throwable();
33+
$status = StatusDetector::getStatusForFailure($throwable);
34+
35+
$this->reporter->updateStatus($test, $status, $throwable->message(), $throwable->asString());
3236
}
3337
}

src/Events/TestFailedSubscriber.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPUnit\Event\Test\Failed;
99
use PHPUnit\Event\Test\FailedSubscriber;
1010
use Qase\PHPUnitReporter\QaseReporterInterface;
11+
use Qase\PHPUnitReporter\StatusDetector;
1112

1213
final class TestFailedSubscriber implements FailedSubscriber
1314
{
@@ -28,6 +29,9 @@ public function notify(Failed $event): void
2829
return;
2930
}
3031

31-
$this->reporter->updateStatus($test, 'failed', $event->throwable()->message(), $event->throwable()->asString());
32+
$throwable = $event->throwable();
33+
$status = StatusDetector::getStatusForFailure($throwable);
34+
35+
$this->reporter->updateStatus($test, $status, $throwable->message(), $throwable->asString());
3236
}
3337
}

src/Events/TestMarkedIncompleteSubscriber.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPUnit\Event\Test\MarkedIncomplete;
99
use PHPUnit\Event\Test\MarkedIncompleteSubscriber;
1010
use Qase\PHPUnitReporter\QaseReporterInterface;
11+
use Qase\PHPUnitReporter\StatusDetector;
1112

1213
final class TestMarkedIncompleteSubscriber implements MarkedIncompleteSubscriber
1314
{
@@ -28,6 +29,9 @@ public function notify(MarkedIncomplete $event): void
2829
return;
2930
}
3031

31-
$this->reporter->updateStatus($test, 'failed', $event->throwable()->message(), $event->throwable()->asString());
32+
$throwable = $event->throwable();
33+
$status = StatusDetector::getStatusForFailure($throwable);
34+
35+
$this->reporter->updateStatus($test, $status, $throwable->message(), $throwable->asString());
3236
}
3337
}

src/Events/TestWarningTriggeredSubscriber.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ public function notify(WarningTriggered $event): void
2828
return;
2929
}
3030

31-
$this->reporter->updateStatus($test, 'failed', $event->message());
31+
$this->reporter->updateStatus($test, 'invalid', $event->message());
3232
}
3333
}

src/StatusDetector.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Qase\PHPUnitReporter;
6+
7+
use PHPUnit\Event\Code\Throwable as PHPUnitThrowable;
8+
use PHPUnit\Framework\AssertionFailedError;
9+
use PHPUnit\Framework\ExpectationFailedException;
10+
11+
/**
12+
* Class for detecting test failure types to determine appropriate status
13+
*/
14+
class StatusDetector
15+
{
16+
/**
17+
* Determine if the throwable represents an assertion failure
18+
*
19+
* @param PHPUnitThrowable $throwable The exception/error that caused test failure
20+
* @return bool True if it's an assertion failure, false otherwise
21+
*/
22+
public static function isAssertionFailure(PHPUnitThrowable $throwable): bool
23+
{
24+
$className = $throwable->className();
25+
26+
return $className === AssertionFailedError::class ||
27+
$className === ExpectationFailedException::class ||
28+
is_subclass_of($className, AssertionFailedError::class) ||
29+
is_subclass_of($className, ExpectationFailedException::class);
30+
}
31+
32+
/**
33+
* Get the appropriate status for a test failure
34+
*
35+
* @param PHPUnitThrowable $throwable The exception/error that caused test failure
36+
* @return string 'failed' for assertion failures, 'invalid' for other errors
37+
*/
38+
public static function getStatusForFailure(PHPUnitThrowable $throwable): string
39+
{
40+
return self::isAssertionFailure($throwable) ? 'failed' : 'invalid';
41+
}
42+
}

tests/StatusDetectorTest.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests;
6+
7+
use PHPUnit\Event\Code\Throwable as PHPUnitThrowable;
8+
use PHPUnit\Framework\AssertionFailedError;
9+
use PHPUnit\Framework\ExpectationFailedException;
10+
use PHPUnit\Framework\TestCase;
11+
use Qase\PHPUnitReporter\StatusDetector;
12+
13+
class StatusDetectorTest extends TestCase
14+
{
15+
public function testIsAssertionFailureWithAssertionFailedError(): void
16+
{
17+
$throwable = $this->createPHPUnitThrowable(AssertionFailedError::class, 'Test assertion failed');
18+
19+
$this->assertTrue(StatusDetector::isAssertionFailure($throwable));
20+
}
21+
22+
public function testIsAssertionFailureWithExpectationFailedException(): void
23+
{
24+
$throwable = $this->createPHPUnitThrowable(ExpectationFailedException::class, 'Expected value was not equal to actual value');
25+
26+
$this->assertTrue(StatusDetector::isAssertionFailure($throwable));
27+
}
28+
29+
public function testIsNotAssertionFailureWithGenericException(): void
30+
{
31+
$throwable = $this->createPHPUnitThrowable(\Exception::class, 'Generic exception occurred');
32+
33+
$this->assertFalse(StatusDetector::isAssertionFailure($throwable));
34+
}
35+
36+
public function testIsNotAssertionFailureWithRuntimeException(): void
37+
{
38+
$throwable = $this->createPHPUnitThrowable(\RuntimeException::class, 'Runtime error occurred');
39+
40+
$this->assertFalse(StatusDetector::isAssertionFailure($throwable));
41+
}
42+
43+
public function testGetStatusForFailureWithAssertionFailedError(): void
44+
{
45+
$throwable = $this->createPHPUnitThrowable(AssertionFailedError::class, 'Test assertion failed');
46+
47+
$this->assertEquals('failed', StatusDetector::getStatusForFailure($throwable));
48+
}
49+
50+
public function testGetStatusForFailureWithExpectationFailedException(): void
51+
{
52+
$throwable = $this->createPHPUnitThrowable(ExpectationFailedException::class, 'Expected value was not equal to actual value');
53+
54+
$this->assertEquals('failed', StatusDetector::getStatusForFailure($throwable));
55+
}
56+
57+
public function testGetStatusForFailureWithGenericException(): void
58+
{
59+
$throwable = $this->createPHPUnitThrowable(\Exception::class, 'Generic exception occurred');
60+
61+
$this->assertEquals('invalid', StatusDetector::getStatusForFailure($throwable));
62+
}
63+
64+
public function testGetStatusForFailureWithRuntimeException(): void
65+
{
66+
$throwable = $this->createPHPUnitThrowable(\RuntimeException::class, 'Runtime error occurred');
67+
68+
$this->assertEquals('invalid', StatusDetector::getStatusForFailure($throwable));
69+
}
70+
71+
private function createPHPUnitThrowable(string $className, string $message): PHPUnitThrowable
72+
{
73+
return new PHPUnitThrowable(
74+
$className,
75+
$message,
76+
$message,
77+
'Stack trace here',
78+
null
79+
);
80+
}
81+
}

0 commit comments

Comments
 (0)