{"record":{"id":"9207a0c09deaf1d5","repo":"sebastianbergmann/phpunit","slug":"class-s-is-an-enumeration-and-cannot-be-doubled","errorCode":null,"errorMessage":"Class \"%s\" is an enumeration and cannot be doubled","messagePattern":"Class \"(.+?)\" is an enumeration and cannot be doubled","errorType":"exception","errorClass":"ClassIsEnumerationException","httpStatus":null,"severity":"error","filePath":"src/Framework/MockObject/Generator/Generator.php","lineNumber":390,"sourceCode":"            $type,\n            $mockClassName,\n            $testDoubleClassPrefix,\n        );\n\n        if (class_exists($_mockClassName['fullClassName'])) {\n            $isClass = true;\n        } elseif (interface_exists($_mockClassName['fullClassName'])) {\n            $isInterface = true;\n        }\n\n        $class = $this->reflectClass($_mockClassName['fullClassName']);\n\n        if ($class->isAnonymous()) {\n            throw new ClassIsAnonymousException($_mockClassName['fullClassName']);\n        }\n\n        if ($class->isEnum()) {\n            throw new ClassIsEnumerationException($_mockClassName['fullClassName']);\n        }\n\n        if ($class->isFinal()) {\n            throw new ClassIsFinalException($_mockClassName['fullClassName']);\n        }\n\n        if ($class->isReadOnly()) {\n            $isReadonly = true;\n        }\n\n        // @see https://github.com/sebastianbergmann/phpunit/issues/2995\n        if ($isInterface && $class->implementsInterface(Throwable::class)) {\n            $actualClassName        = Exception::class;\n            $additionalInterfaces[] = $class->getName();\n            $isInterface            = false;\n            $class                  = $this->reflectClass($actualClassName);\n\n            foreach ($this->userDefinedInterfaceMethods($_mockClassName['fullClassName']) as $method) {","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/MockObject/Generator/Generator.php#L372-L408","documentation":"PHPUnit cannot create test doubles for enums: ReflectionClass::isEnum() on the target type triggers this exception. Enums are final-like constructs with singleton cases; the generated-subclass strategy of the mock generator cannot apply to them.","triggerScenarios":"createMock(SomeEnum::class) or createStub(SomeEnum::class) where SomeEnum is a PHP 8.1 enum (pure enum or backed enum); also passing an enum name string through MockBuilder::getMockBuilder().","commonSituations":"Codebases adopting enums for status/type fields and tests still trying to mock them like old constants/class combinations; attempting to stub an enum that carries an interface (enum implements FooInterface) hoping to fake behavior; data providers passing enum names.","solutions":["Use a real enum case in the test instead of a mock (enums are cheap immutable values)","If the enum implements an interface, mock the interface: createMock(FooInterface::class), since the SUT should type-hint the interface","Refactor logic that 'needs' a mocked enum behind an injectable collaborator and mock that"],"exampleFix":"// before\n$status = $this->createMock(OrderStatus::class); // enum -> exception\n\n// after\n$status = OrderStatus::Paid;\n// or, when the enum implements an interface:\n$status = $this->createMock(HasLabel::class);","handlingStrategy":"validation","validationCode":"if ((new ReflectionClass($type))->isEnum()) {\n    // Enums are plain values: use a real case instead of mocking\n    $value = constant($type . '::' . $caseName);\n}\n$mock = $this->createMock($type);","typeGuard":"function isMockableType(string $type): bool\n{\n    if (!class_exists($type) && !interface_exists($type)) {\n        return false;\n    }\n    $r = new ReflectionClass($type);\n    return !$r->isAnonymous() && !$r->isEnum() && !$r->isFinal();\n}","tryCatchPattern":null,"preventionTips":["Use real enum cases in tests — they are immutable values, not collaborators","When enum behavior must be faked, mock the interface the enum implements and type-hint that interface in the SUT"],"tags":["php","phpunit","mockbuilder","enum","createmock"],"backgroundTag":"unmockable-type","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}