sebastianbergmann/phpunit · error · ComparisonMethodDoesNotExistException

Comparison method %s::%s() does not exist.

Error message

Comparison method %s::%s() does not exist.

What it means

PHPUnit's assertObjectEquals() does not compare objects itself; it delegates to a user-defined comparison method on the actual object (default name 'equals'). Before calling it, the ObjectEquals constraint reflects on the actual object's class and requires the configured method to exist. If ReflectionObject::hasMethod() fails, this exception is thrown, meaning the actual value's class has no equals() (or custom-named) method.

Source

Thrown at src/Framework/Constraint/Object/ObjectEquals.php:75

    /**
     * @throws ActualValueIsNotAnObjectException
     * @throws ComparisonMethodDoesNotAcceptParameterTypeException
     * @throws ComparisonMethodDoesNotDeclareBoolReturnTypeException
     * @throws ComparisonMethodDoesNotDeclareExactlyOneParameterException
     * @throws ComparisonMethodDoesNotDeclareParameterTypeException
     * @throws ComparisonMethodDoesNotExistException
     */
    protected function matches(mixed $other): bool
    {
        if (!is_object($other)) {
            throw new ActualValueIsNotAnObjectException;
        }

        $object = new ReflectionObject($other);

        if (!$object->hasMethod($this->method)) {
            throw new ComparisonMethodDoesNotExistException(
                $other::class,
                $this->method,
            );
        }

        $method = $object->getMethod($this->method);

        if (!$method->hasReturnType()) {
            throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(
                $other::class,
                $this->method,
            );
        }

        $returnType = $method->getReturnType();

        if (!$returnType instanceof ReflectionNamedType) {
            throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException(

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Add a public instance method named equals (or the name passed as 3rd argument) to the actual object's class: `public function equals(self $other): bool`
  2. If your method has a different name (e.g. isEqualTo), pass it explicitly: assertObjectEquals($expected, $actual, 'isEqualTo')
  3. If you cannot modify the class, fall back to assertEquals($expected, $actual) which compares structurally without a custom method

Example fix

// before
$this->assertObjectEquals($expectedMoney, $actualMoney);
// RuntimeException-ish failure: Comparison method Money::equals() does not exist.

class Money { /* no equals() */ }

// after
class Money
{
    public function equals(self $other): bool
    {
        return $this->amount === $other->amount && $this->currency === $other->currency;
    }
}
$this->assertObjectEquals($expectedMoney, $actualMoney);
Defensive patterns

Strategy: type-guard

Type guard

function hasComparisonMethod(object $actual, string $method = 'equals'): bool
{
    return (new ReflectionObject($actual))->hasMethod($method);
}

if (!hasComparisonMethod($actual, 'equals')) {
    $this->markTestIncomplete(get_class($actual) . ' has no equals() method');
}

Try / catch

use PHPUnit\Framework\ComparisonMethodDoesNotExistException;

try {
    $this->assertObjectEquals($expected, $actual);
} catch (ComparisonMethodDoesNotExistException $e) {
    // authoring error: fix the class, do not swallow
    $this->fail('Comparison method missing: ' . $e->getMessage());
}

Prevention

When it happens

Trigger: assertObjectEquals($expected, $actual) where $actual's class declares no public equals() method; or assertObjectEquals($expected, $actual, 'isEqualTo') where 'isEqualTo' does not exist on the actual class (typo, or method only exists on the expected class, or it is defined on a parent the actual object does not extend).

Common situations: Value objects that only implement a static equals() or an isEqualTo() with a different name; test authors assuming assertObjectEquals works like assertEquals and skipping the equals() method; the method exists but on the expected object's class instead of the actual one; PHP 8 constructor-promoted DTOs where equals() was never written.

Related errors


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