sebastianbergmann/phpunit · error · ExpectationFailedException
Expectation for %s failed. %s
Error message
Expectation for %s failed. %s
What it means
Wrapped ExpectationFailedException from Matcher::invoked(): when a real call arrives and the matcher's parametersRule->apply($invocation) fails (the actual arguments do not satisfy with() constraints), PHPUnit rethrows with 'Expectation for <method> failed.' prefixed to the original parameter mismatch message, preserving the comparison failure. It means the method was called, but with different arguments than the expectation asserts.
Source
Thrown at src/Framework/MockObject/Runtime/Matcher.php:139
throw new MethodNameNotConfiguredException;
}
if ($this->afterMatchBuilderId !== null) {
$matcher = $invocation->object()
->__phpunit_getInvocationHandler()
->lookupMatcher($this->afterMatchBuilderId);
if ($matcher === null) {
throw new MatchBuilderNotFoundException($this->afterMatchBuilderId);
}
}
$this->invocationRule->invoked($invocation);
try {
$this->parametersRule?->apply($invocation);
} catch (ExpectationFailedException $e) {
throw new ExpectationFailedException(
sprintf(
"Expectation for %s failed.\n%s",
$this->methodNameRule->failureDescription($this->className),
$e->getMessage(),
),
$e->getComparisonFailure(),
);
}
if ($this->stub !== null) {
return $this->stub->invoke($invocation);
}
return $invocation->generateReturnValue();
}
/**
* @throws ExpectationFailedExceptionView on GitHub (pinned to f123cdb2a2)
Solutions
- Read the nested message: it shows the expected vs actual argument values — align the expectation with the real arguments (or fix the production code that passes wrong ones).
- For object arguments, either implement value equality on the DTO or use a callback constraint: ->with($this->callback(fn ($m) => $m->amount === 100)).
- Use $this->identicalTo($x) when identity is the real requirement, and $this->equalTo($x) (default) for structural equality.
- If argument order varies, withParameterSetsInAnyOrder([...]) replaces several brittle with() rules.
Example fix
// before
$mailer = $this->createMock(Mailer::class);
$mailer->expects($this->once())
->method('send')
->with('Hello') // code actually sends 'Hello!'
->willReturn(true);
// after
$mailer->expects($this->once())
->method('send')
->with('Hello!')
->willReturn(true); Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check the exact constraint against the value you expect the subject to pass $expected = 'Hello!'; $actual = $subject->buildGreeting(); $this->assertSame($expected, $actual); // fail early with a clean diff before the mock call
Type guard
// constraints double as guards: verify a value satisfies the with() rule before the call
$constraint = $this->identicalTo($token);
if (!$constraint->evaluate($candidate, '', true)) {
throw new RuntimeException('subject will pass a different token');
} Try / catch
try {
$subject->run($mock);
} catch (PHPUnit\Framework\ExpectationFailedException $e) {
// assertion failure during the call: inspect getComparisonFailure() diff,
// fix the with() constraints to match reality, then remove the catch
} Prevention
- Read the nested message — it contains expected vs actual argument values; align the expectation with reality.
- For object arguments, use callback constraints comparing fields instead of relying on equality/identity surprises.
- Avoid literals for runtime-computed arguments (timestamps, ids); constrain structurally.
When it happens
Trigger: Expectation ->method('transfer')->with(100, 'EUR') but the code under test calls transfer(50, 'EUR'); identical() vs equalTo() semantics (with() defaults to equal, not same) so same-looking objects differ; float/string coercion mismatches under strict comparison inside the parameter rule.
Common situations: The subject transforms arguments before delegating to the collaborator (multiplied amounts, trimmed strings, wrapped DTOs); expectations copied from a spec where values were different; with(new Money(100)) comparing object identity instead of equality; timezone/locale formatting changing string arguments.
Related errors
- Parameters for method "%s" are already configured for anothe
- %s was expected to be %s but was %s.
- Cannot double method with invalid name "%s"
- Cannot double using a method list that contains duplicates:
- Cannot use "%s" as the name of a test double class because i
AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23).
Data as JSON: /api/errors/3ed5cf0c948bbe68.
Report an issue: GitHub.