sebastianbergmann/phpunit · error · Exception

Class %s is not a subclass of %s

Error message

Class %s is not a subclass of %s

What it means

Thrown by TestSuite::addTestSuite() when the given class is concrete but does not extend PHPUnit\Framework\TestCase (checked with is_subclass_of()). TestSuite instances aggregate actual tests, so any class registered as a test suite must be a TestCase subclass.

Source

Thrown at src/Framework/TestSuite.php:220

     * @param positive-int              $maxAttempts
     *
     * @throws Exception
     */
    public function addTestSuite(ReflectionClass $testClass, array $groups = [], int $numberOfRuns = 1, int $maxAttempts = 1): void
    {
        $className = $testClass->getName();

        if ($testClass->isAbstract()) {
            throw new Exception(
                sprintf(
                    'Class %s is abstract',
                    $className,
                ),
            );
        }

        if (!is_subclass_of($className, TestCase::class)) {
            throw new Exception(
                sprintf(
                    'Class %s is not a subclass of %s',
                    $className,
                    TestCase::class,
                ),
            );
        }

        $this->addTest(self::fromClassReflector($testClass, $groups, $numberOfRuns, $maxAttempts), $groups);
    }

    /**
     * Wraps both <code>addTest()</code> and <code>addTestSuite</code>
     * as well as the separate import statements for the user's convenience.
     *
     * If the named file cannot be read or there are no new tests that can be
     * added, a <code>PHPUnit\Framework\WarningTestCase</code> will be created instead,
     * leaving the current test run untouched.

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Pass only classes that extend PHPUnit\Framework\TestCase to addTestSuite()
  2. Rename support classes in the tests directory so they do not match the test suffix/prefix your loader scans (e.g. 'Helper' instead of 'Test')
  3. Exclude the directory or file containing non-test classes in phpunit.xml

Example fix

// before
$suite->addTestSuite(new ReflectionClass(TestDataFactory::class)); // not a TestCase

// after
$suite->addTestSuite(new ReflectionClass(UserRepositoryTest::class));
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_subclass_of($className, \PHPUnit\Framework\TestCase::class)) {
    // not a test class: do not register it, log it for cleanup instead
}

Type guard

function isRunnableTestClass(ReflectionClass $class): bool
{
    return !$class->isAbstract()
        && $class->isSubclassOf(\PHPUnit\Framework\TestCase::class);
}

Prevention

When it happens

Trigger: Calling addTestSuite(new ReflectionClass($class)) where $class is a plain helper, fixture, or data class; loading a tests directory that contains non-test classes (helpers, traits consumers, DTOs) whose files match the test file naming convention.

Common situations: Helper classes or support code stored in the tests directory with names like *Test.php or *TestCase.php; typos when referencing a test class name; custom runners registering arbitrary classes.

Related errors


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/3bc333bb100f1f64. Report an issue: GitHub.