diff --git a/.psalm/baseline.xml b/.psalm/baseline.xml
index 3476b5bded9..5fb77ddafe9 100644
--- a/.psalm/baseline.xml
+++ b/.psalm/baseline.xml
@@ -1044,18 +1044,13 @@
-
- LegacyTestResult
- LegacyTestResult
- LegacyTestResult
- LegacyTestResult
- LegacyTestResult
- LegacyTestResult
- LegacyTestResult
-
resourceUsageSinceStartOfRequest
+
+ assert($test instanceof TestMethod)
+ assert($test instanceof TestMethod)
+
diff --git a/src/Framework/TestSuite.php b/src/Framework/TestSuite.php
index 0313f96f3d0..acc78800ac8 100644
--- a/src/Framework/TestSuite.php
+++ b/src/Framework/TestSuite.php
@@ -103,18 +103,10 @@ public static function fromClassReflector(ReflectionClass $class): static
$constructor = $class->getConstructor();
if ($constructor !== null && !$constructor->isPublic()) {
- $message = sprintf(
- 'Class "%s" has no public constructor.',
- $class->getName()
- );
-
- Event\Facade::emitter()->testRunnerTriggeredWarning($message);
-
- $testSuite->addTest(
- new WarningTestCase(
- $class->getName(),
- '',
- $message
+ Event\Facade::emitter()->testRunnerTriggeredWarning(
+ sprintf(
+ 'Class "%s" has no public constructor.',
+ $class->getName()
)
);
@@ -138,18 +130,10 @@ public static function fromClassReflector(ReflectionClass $class): static
}
if (count($testSuite) === 0) {
- $message = sprintf(
- 'No tests found in class "%s".',
- $class->getName()
- );
-
- Event\Facade::emitter()->testRunnerTriggeredWarning($message);
-
- $testSuite->addTest(
- new WarningTestCase(
- $class->getName(),
- '',
- $message
+ Event\Facade::emitter()->testRunnerTriggeredWarning(
+ sprintf(
+ 'No tests found in class "%s".',
+ $class->getName()
)
);
}
diff --git a/src/Runner/TestResult/Collector.php b/src/Runner/TestResult/Collector.php
index 73493afb241..914d827f2fc 100644
--- a/src/Runner/TestResult/Collector.php
+++ b/src/Runner/TestResult/Collector.php
@@ -235,6 +235,19 @@ public function hasTestMarkedIncompleteEvents(): bool
return !empty($this->testMarkedIncompleteEvents);
}
+ public function hasTestRunnerTriggeredWarningEvents(): bool
+ {
+ return !empty($this->testRunnerTriggeredWarningEvents);
+ }
+
+ /**
+ * @psalm-return list
+ */
+ public function testRunnerTriggeredWarningEvents(): array
+ {
+ return $this->testRunnerTriggeredWarningEvents;
+ }
+
/**
* @psalm-return list
*/
diff --git a/src/TextUI/Application.php b/src/TextUI/Application.php
index 203648d2506..1bf6241ccbf 100644
--- a/src/TextUI/Application.php
+++ b/src/TextUI/Application.php
@@ -249,6 +249,15 @@ private function handleArguments(array $argv): TestSuite
exit(self::EXCEPTION_EXIT);
}
+ if ($testSuite->isEmpty() &&
+ ($arguments->hasArgument() || $this->xmlConfiguration->phpunit()->hasDefaultTestSuite())) {
+ $this->printVersionString();
+
+ print 'No tests found.' . PHP_EOL;
+
+ exit(self::EXCEPTION_EXIT);
+ }
+
if ($configuration->hasCoverageReport() || $arguments->hasWarmCoverageCache()) {
CodeCoverageFilterRegistry::init($arguments, $this->xmlConfiguration);
}
diff --git a/src/TextUI/ResultPrinter.php b/src/TextUI/ResultPrinter.php
index a6515188e8a..fd8363562f5 100644
--- a/src/TextUI/ResultPrinter.php
+++ b/src/TextUI/ResultPrinter.php
@@ -10,14 +10,19 @@
namespace PHPUnit\TextUI;
use const PHP_EOL;
-use PHPUnit\Framework\RiskyTest;
-use PHPUnit\Framework\TestCase;
-use PHPUnit\Framework\TestFailure;
-use PHPUnit\Framework\TestResult as LegacyTestResult;
+use function assert;
+use function count;
+use function sprintf;
+use function str_starts_with;
+use function strlen;
+use function substr;
+use function trim;
+use PHPUnit\Event\Code\Test;
+use PHPUnit\Event\Code\TestMethod;
+use PHPUnit\Event\Test\BeforeFirstTestMethodErrored;
use PHPUnit\TestRunner\TestResult\TestResult;
use PHPUnit\Util\Color;
use PHPUnit\Util\Printer;
-use ReflectionMethod;
use SebastianBergmann\Timer\ResourceUsageFormatter;
/**
@@ -26,36 +31,36 @@
final class ResultPrinter
{
private Printer $printer;
- private bool $colors;
+ private bool $colorizeOutput;
private bool $displayDetailsOnIncompleteTests;
private bool $displayDetailsOnSkippedTests;
- private bool $reverse;
- private bool $defectListPrinted = false;
+ private bool $displayDefectsInReverseOrder;
+ private bool $listPrinted = false;
- public function __construct(Printer $printer, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $colors, bool $reverse)
+ public function __construct(Printer $printer, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $colorizeOutput, bool $displayDefectsInReverseOrder)
{
$this->printer = $printer;
$this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests;
$this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests;
- $this->colors = $colors;
- $this->reverse = $reverse;
+ $this->colorizeOutput = $colorizeOutput;
+ $this->displayDefectsInReverseOrder = $displayDefectsInReverseOrder;
}
- public function printResult(TestResult $result, LegacyTestResult $legacyResult): void
+ public function printResult(TestResult $result): void
{
$this->printHeader($result);
- $this->printTestsWithErrors($result, $legacyResult);
- $this->printTestsWithWarnings($result, $legacyResult);
- $this->printTestsWithFailedAssertions($result, $legacyResult);
- $this->printRiskyTests($result, $legacyResult);
+ $this->printTestsWithErrors($result);
+ $this->printTestsWithWarnings($result);
+ $this->printTestsWithFailedAssertions($result);
+ $this->printRiskyTests($result);
if ($this->displayDetailsOnIncompleteTests) {
- $this->printIncompleteTests($result, $legacyResult);
+ $this->printIncompleteTests($result);
}
if ($this->displayDetailsOnSkippedTests) {
- $this->printSkippedTests($result, $legacyResult);
+ $this->printSkippedTests($result);
}
$this->printFooter($result);
@@ -73,48 +78,140 @@ private function printHeader(TestResult $result): void
}
}
- private function printTestsWithErrors(TestResult $result, LegacyTestResult $legacyResult): void
+ private function printTestsWithErrors(TestResult $result): void
{
- $this->printDefects($legacyResult->errors(), 'error');
- }
+ if (!$result->hasTestErroredEvents()) {
+ return;
+ }
- private function printTestsWithFailedAssertions(TestResult $result, LegacyTestResult $legacyResult): void
- {
- $this->printDefects($legacyResult->failures(), 'failure');
+ $elements = [];
+
+ foreach ($result->testErroredEvents() as $event) {
+ if ($event instanceof BeforeFirstTestMethodErrored) {
+ $title = $event->testClassName();
+ } else {
+ $title = $this->name($event->test());
+ }
+
+ $elements[] = [
+ 'title' => $title,
+ 'body' => $event->throwable()->asString(),
+ ];
+ }
+
+ $this->printList(count($elements), $elements, 'error');
}
- private function printTestsWithWarnings(TestResult $result, LegacyTestResult $legacyResult): void
+ private function printTestsWithFailedAssertions(TestResult $result): void
{
- $this->printDefects($legacyResult->warnings(), 'warning');
+ if (!$result->hasTestFailedEvents()) {
+ return;
+ }
+
+ $elements = [];
+
+ foreach ($result->testFailedEvents() as $event) {
+ $body = $event->throwable()->asString();
+
+ if (str_starts_with($body, 'AssertionError: ')) {
+ $body = substr($body, strlen('AssertionError: '));
+ }
+
+ $elements[] = [
+ 'title' => $this->name($event->test()),
+ 'body' => $body,
+ ];
+ }
+
+ $this->printList(count($elements), $elements, 'failure');
}
- private function printRiskyTests(TestResult $result, LegacyTestResult $legacyResult): void
+ private function printTestsWithWarnings(TestResult $result): void
{
- $this->printDefects($legacyResult->risky(), 'risky test');
}
- private function printIncompleteTests(TestResult $result, LegacyTestResult $legacyResult): void
+ private function printRiskyTests(TestResult $result): void
{
- $this->printDefects($legacyResult->notImplemented(), 'incomplete test');
+ if (!$result->hasTestConsideredRiskyEvents()) {
+ return;
+ }
+
+ $elements = [];
+
+ foreach ($result->testConsideredRiskyEvents() as $reasons) {
+ foreach ($reasons as $reason) {
+ $body = $reason->message() . PHP_EOL;
+ $test = $reason->test();
+
+ if ($test->isTestMethod()) {
+ assert($test instanceof TestMethod);
+
+ $body .= sprintf(
+ '%s%s:%d%s',
+ PHP_EOL,
+ $test->file(),
+ $test->line(),
+ PHP_EOL
+ );
+ }
+
+ $elements[] = [
+ 'title' => $this->name($test),
+ 'body' => $body,
+ ];
+ }
+ }
+
+ $this->printList($result->numberOfTestsWithTestConsideredRiskyEvents(), $elements, 'risky test');
}
- private function printSkippedTests(TestResult $result, LegacyTestResult $legacyResult): void
+ private function printIncompleteTests(TestResult $result): void
{
- $this->printDefects($legacyResult->skipped(), 'skipped test');
+ if (!$result->hasTestMarkedIncompleteEvents()) {
+ return;
+ }
+
+ $elements = [];
+
+ foreach ($result->testMarkedIncompleteEvents() as $event) {
+ $elements[] = [
+ 'title' => $this->name($event->test()),
+ 'body' => $event->throwable()->asString(),
+ ];
+ }
+
+ $this->printList(count($elements), $elements, 'incomplete test');
}
- private function printDefects(array $defects, string $type): void
+ private function printSkippedTests(TestResult $result): void
{
- $count = count($defects);
-
- if ($count === 0) {
+ if (!$result->hasTestSkippedEvents()) {
return;
}
- if ($this->defectListPrinted) {
+ $elements = [];
+
+ foreach ($result->testSkippedEvents() as $event) {
+ $elements[] = [
+ 'title' => $this->name($event->test()),
+ 'body' => $event->message(),
+ ];
+ }
+
+ $this->printList(count($elements), $elements, 'skipped test');
+ }
+
+ /**
+ * @psalm-param list $elements
+ */
+ private function printList(int $count, array $elements, string $type): void
+ {
+ if ($this->listPrinted) {
$this->printer->print("\n--\n\n");
}
+ $this->listPrinted = true;
+
$this->printer->print(
sprintf(
"There %s %d %s%s:\n",
@@ -127,64 +224,27 @@ private function printDefects(array $defects, string $type): void
$i = 1;
- if ($this->reverse) {
- $defects = array_reverse($defects);
+ if ($this->displayDefectsInReverseOrder) {
+ $elements = array_reverse($elements);
}
- foreach ($defects as $defect) {
- $this->printDefect($defect, $i++);
+ foreach ($elements as $element) {
+ $this->printListElement($i++, $element['title'], $element['body']);
}
-
- $this->defectListPrinted = true;
}
- private function printDefect(TestFailure $defect, int $index): void
- {
- $this->printDefectHeader($index, $defect->getTestName());
- $this->printDefectTrace($defect);
- }
-
- private function printDefectHeader(int $index, string $testName): void
+ private function printListElement(int $number, string $title, string $body): void
{
$this->printer->print(
sprintf(
- "\n%d) %s\n",
- $index,
- $testName
+ "\n%d) %s\n%s\n",
+ $number,
+ $title,
+ trim($body)
)
);
}
- private function printDefectTrace(TestFailure $defect): void
- {
- $e = $defect->thrownException();
-
- $this->printer->print((string) $e);
-
- if ($defect->thrownException() instanceof RiskyTest) {
- $test = $defect->failedTest();
-
- assert($test instanceof TestCase);
-
- /** @noinspection PhpUnhandledExceptionInspection */
- $reflector = new ReflectionMethod($test::class, $test->getName(false));
-
- $this->printer->print(
- sprintf(
- '%s%s:%d%s',
- PHP_EOL,
- $reflector->getFileName(),
- $reflector->getStartLine(),
- PHP_EOL
- )
- );
- } else {
- while ($e = $e->getPrevious()) {
- $this->printer->print("\nCaused by\n" . $e);
- }
- }
- }
-
private function printFooter(TestResult $result): void
{
if ($result->numberOfTestsRun() === 0) {
@@ -280,7 +340,7 @@ private function printCountString(int $count, string $name, string $color, bool
private function printWithColor(string $color, string $buffer, bool $lf = true): void
{
- if ($this->colors) {
+ if ($this->colorizeOutput) {
$buffer = Color::colorizeTextBox($color, $buffer);
}
@@ -290,4 +350,15 @@ private function printWithColor(string $color, string $buffer, bool $lf = true):
$this->printer->print(PHP_EOL);
}
}
+
+ private function name(Test $test): string
+ {
+ if ($test->isTestMethod()) {
+ assert($test instanceof TestMethod);
+
+ return $test->nameWithClass();
+ }
+
+ return $test->name();
+ }
}
diff --git a/src/TextUI/TestRunner.php b/src/TextUI/TestRunner.php
index 1005d9f9225..be2e5b1e1d0 100644
--- a/src/TextUI/TestRunner.php
+++ b/src/TextUI/TestRunner.php
@@ -393,7 +393,7 @@ public function run(TestSuite $suite): TestResult
$result = Facade::result();
if (isset($resultPrinter)) {
- $resultPrinter->printResult($result, $legacyResult);
+ $resultPrinter->printResult($result);
}
if (isset($junitXmlLogger)) {
diff --git a/tests/_files/NotVoidTestCase.php b/tests/_files/NotVoidTestCase.php
deleted file mode 100644
index e246f11085d..00000000000
--- a/tests/_files/NotVoidTestCase.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-namespace PHPUnit\TestFixture;
-
-use PHPUnit\Framework\TestCase;
-
-class NotVoidTestCase extends TestCase
-{
-}
diff --git a/tests/end-to-end/event/_files/PrivateTest.php b/tests/end-to-end/event/_files/PrivateTest.php
deleted file mode 100644
index 0d9517422d2..00000000000
--- a/tests/end-to-end/event/_files/PrivateTest.php
+++ /dev/null
@@ -1,19 +0,0 @@
-
- *
- * 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 PrivateTest extends TestCase
-{
- private function __construct()
- {
- }
-}
diff --git a/tests/end-to-end/event/test-class-with-private-constructor.phpt b/tests/end-to-end/event/test-class-with-private-constructor.phpt
deleted file mode 100644
index 7cb46be096f..00000000000
--- a/tests/end-to-end/event/test-class-with-private-constructor.phpt
+++ /dev/null
@@ -1,42 +0,0 @@
---TEST--
-The right events are emitted in the right order for a test class that has a non-public constructor
---SKIPIF--
-
%sIssue765Test.php:%d
diff --git a/tests/end-to-end/risky-tests/global-state.phpt b/tests/end-to-end/risky-tests/global-state.phpt
index d4666a1db2c..00fad354ae8 100644
--- a/tests/end-to-end/risky-tests/global-state.phpt
+++ b/tests/end-to-end/risky-tests/global-state.phpt
@@ -22,6 +22,7 @@ Time: %s, Memory: %s
There was 1 risky test:
1) PHPUnit\TestFixture\RiskyTests\GlobalStateManipulatorTest::testManipulatesGlobalState
+This test modified global state but was not expected to do so
--- Global variables before the test
+++ Global variables after the test
@@ @@
@@ -29,5 +30,7 @@ There was 1 risky test:
+ 'foo' => 'bar'
%A
+%s:%d
+
OK, but incomplete, skipped, or risky tests!
Tests: 1, Assertions: 1, Risky: 1.
diff --git a/tests/unit/Framework/TestSuiteTest.php b/tests/unit/Framework/TestSuiteTest.php
index faae1ea6ff0..f30d6d5eb4a 100644
--- a/tests/unit/Framework/TestSuiteTest.php
+++ b/tests/unit/Framework/TestSuiteTest.php
@@ -19,7 +19,6 @@
use PHPUnit\TestFixture\DoubleTestCase;
use PHPUnit\TestFixture\MultiDependencyTest;
use PHPUnit\TestFixture\NotPublicTestCase;
-use PHPUnit\TestFixture\NotVoidTestCase;
use PHPUnit\TestFixture\PreConditionAndPostConditionTest;
use PHPUnit\TestFixture\Success;
use ReflectionClass;
@@ -35,13 +34,6 @@ public function testNotPublicTestCase(): void
$this->assertCount(1, $suite);
}
- public function testNotVoidTestCase(): void
- {
- $suite = TestSuite::fromClassName(NotVoidTestCase::class);
-
- $this->assertCount(1, $suite);
- }
-
public function testBeforeAndAfterAnnotations(): void
{
$test = TestSuite::fromClassName(BeforeAndAfterTest::class);
diff --git a/tests/unit/Runner/TestSuiteSorterTest.php b/tests/unit/Runner/TestSuiteSorterTest.php
index a4055abd1f2..cdd93ded2c3 100644
--- a/tests/unit/Runner/TestSuiteSorterTest.php
+++ b/tests/unit/Runner/TestSuiteSorterTest.php
@@ -17,7 +17,6 @@
use PHPUnit\Framework\TestStatus\TestStatus;
use PHPUnit\Framework\TestSuite;
use PHPUnit\Runner\ResultCache\DefaultResultCache;
-use PHPUnit\TestFixture\EmptyTestCaseTest;
use PHPUnit\TestFixture\FailureTest;
use PHPUnit\TestFixture\MultiDependencyTest;
use PHPUnit\TestFixture\NotReorderableTest;
@@ -577,28 +576,6 @@ public function defectsSorterOptionsProvider(): array
];
}
- /**
- * @see https://github.com/lstrojny/phpunit-clever-and-smart/issues/38
- */
- public function testCanHandleSuiteWithEmptyTestCase(): void
- {
- $suite = TestSuite::empty();
- $suite->addTestSuite(new ReflectionClass(EmptyTestCaseTest::class));
-
- $sorter = new TestSuiteSorter;
-
- $sorter->reorderTestsInSuite($suite, TestSuiteSorter::ORDER_DEFAULT, false, TestSuiteSorter::ORDER_DEFAULT);
-
- $this->assertSame(EmptyTestCaseTest::class, $suite->tests()[0]->getName());
- $this->assertSame(
- sprintf(
- 'No tests found in class "%s".',
- EmptyTestCaseTest::class
- ),
- $suite->tests()[0]->tests()[0]->getMessage()
- );
- }
-
public function suiteSorterOptionPermutationsProvider(): array
{
$orderValues = [TestSuiteSorter::ORDER_DEFAULT, TestSuiteSorter::ORDER_REVERSED, TestSuiteSorter::ORDER_RANDOMIZED];