sebastianbergmann/phpunit · error · InvalidClassNameException
Cannot use "%s" as the name of a test double class because i
Error message
Cannot use "%s" as the name of a test double class because it is not a valid PHP class name
What it means
Thrown by Generator::ensureValidNameForTestDoubleClass() when the requested class name for the generated test double is not a valid PHP class name (same identifier regex as method names; empty string is allowed and skips validation). This name comes from the mockClassName argument, e.g. MockBuilder::setMockClassName(). Note the regex has no backslash, so fully-qualified namespaced names are rejected too.
Source
Thrown at src/Framework/MockObject/Generator/Generator.php:734
}
}
if ($methods !== array_unique($methods)) {
throw new DuplicateMethodException($methods);
}
}
/**
* @throws InvalidClassNameException
*/
private function ensureValidNameForTestDoubleClass(string $className): void
{
if ($className === '') {
return;
}
if (preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $className) === 0) {
throw new InvalidClassNameException($className);
}
}
/**
* @throws NameAlreadyInUseException
* @throws ReflectionException
*/
private function ensureNameForTestDoubleClassIsAvailable(string $className): void
{
if ($className === '') {
return;
}
if (class_exists($className, false) ||
interface_exists($className, false) ||
trait_exists($className, false)) {
throw new NameAlreadyInUseException($className);
}View on GitHub (pinned to f123cdb2a2)
Solutions
- Use a bare identifier: letters, digits, underscore, starting with a letter or underscore (setMockClassName('FooMock')).
- Do not include a namespace in the mock class name; PHPUnit generates the class in the global mock namespace.
- If you do not need a specific name, drop setMockClassName() entirely and let PHPUnit pick a unique name.
- Sanitize dynamic names: preg_replace('/[^A-Za-z0-9_]/', '', $name) and prefix with a letter.
Example fix
// before
$mock = $this->getMockBuilder(UserRepo::class)
->setMockClassName('App\\Tests\\User-Repo-Mock')
->getMock();
// after
$mock = $this->getMockBuilder(UserRepo::class)
->setMockClassName('UserRepoMock')
->getMock(); Defensive patterns
Strategy: validation
Validate before calling
$mockClassName = 'RepoMock';
if (!preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $mockClassName)) {
$mockClassName = preg_replace('/[^A-Za-z0-9_]/', '', $mockClassName);
} Type guard
function isPhpClassName(string $name): bool
{
return (bool) preg_match('~\A[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z~', $name);
} Try / catch
try {
$mock = $builder->setMockClassName($name)->getMock();
} catch (PHPUnit\Framework\MockObject\InvalidClassNameException $e) {
// fall back to an auto-generated name: omit setMockClassName()
} Prevention
- Prefer omitting setMockClassName() unless a specific name is required.
- Remember the mock class name must be a single identifier — no namespace separators, no dashes, no leading digit.
- Sanitize data-derived names down to [A-Za-z0-9_] before use.
When it happens
Trigger: $this->getMockBuilder(C::class)->setMockClassName('My-Mock') with hyphens, digits first ('Mock123' is fine, '123Mock' is not), spaces, or a namespaced string 'App\\Mocks\\Foo'; calling Generator::testDouble(..., mockClassName: 'not valid') directly.
Common situations: Passing an existing FQCN as the new mock's class name (expecting namespacing support); building mock class names from test data or slugs that contain dashes; copying a class basename with stray characters; migrating tests that used dynamic class names in old PHPUnit versions.
Related errors
- Cannot double method with invalid name "%s"
- Cannot double using a method list that contains duplicates:
- The name "%s" is already in use
- Trying to configure method "%s" which cannot be configured b
- Method %s may not return value of type %s, its declared retu
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/75e7538256ba7f21.
Report an issue: GitHub.