{"record":{"id":"a71454ee473ff201","repo":"sebastianbergmann/phpunit","slug":"doubled-method-does-not-exist","errorCode":null,"errorMessage":"Doubled method does not exist.","messagePattern":"Doubled method does not exist\\.","errorType":"exception","errorClass":"ExpectationFailedException","httpStatus":null,"severity":"error","filePath":"src/Framework/MockObject/Runtime/Rule/Parameters.php","lineNumber":103,"sourceCode":"        $this->doVerify();\n    }\n\n    public function useAssertionCount(bool $useAssertionCount): void\n    {\n        $this->useAssertionCount = $useAssertionCount;\n    }\n\n    /**\n     * @throws ExpectationFailedException\n     */\n    private function doVerify(): bool\n    {\n        if (isset($this->parameterVerificationResult)) {\n            return $this->guardAgainstDuplicateEvaluationOfParameterConstraints();\n        }\n\n        if ($this->invocation === null) {\n            throw new ExpectationFailedException('Doubled method does not exist.');\n        }\n\n        $invocation           = $this->invocation;\n        $invocationParameters = $invocation->parameters();\n\n        if (count($invocationParameters) < count($this->parameters)) {\n            $message = 'Parameter count for invocation %s is too low.';\n\n            // The user called `->with($this->anything())`, but may have meant\n            // `->withAnyParameters()`.\n            //\n            // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/199\n            if (count($this->parameters) === 1 &&\n                $this->parameters[0]::class === IsAnything::class) {\n                $message .= \"\\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead.\";\n            }\n\n            $this->incrementAssertionCount();","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/MockObject/Runtime/Rule/Parameters.php#L85-L121","documentation":"A misleading PHPUnit message: the doubled method usually does exist — the real condition is that it was never invoked. Parameters::doVerify() throws 'Doubled method does not exist.' when it is asked to verify ->with() constraints but its recorded invocation is still null, which happens when the mocked method was not called at all during the test (apply() never ran). You typically see it when a with() expectation sits on a method the code under test never reaches.","triggerScenarios":"$mock->expects($this->any())->method('foo')->with($this->equalTo(1)) where foo() is never called; verification of a matcher with a Parameters rule but zero invocations; calling the expectation's verify path directly (e.g. $mock->__phpunit_verify() or a failed earlier expectation) before any invocation was recorded. Note expects($this->any()) does not itself verify the count, so the parameter rule's null-invocation check is what fails.","commonSituations":"any()-based expectations on methods that a refactor stopped calling; method name typo in method(); the mock not being injected into the SUT; an exception thrown earlier in the SUT skipping the call; tests asserting arguments for a call that only happens on an untested branch; PHPUnit 10+ where the message text is unchanged but users still grep for it thinking the mock generator failed.","solutions":["Treat it as 'expected method was never called': verify the code under test actually reaches the mocked call.","Confirm the mock instance is the one injected into the SUT and the method() name is spelled correctly.","If the call should not happen, remove the with() constraint (and the whole expectation) — asserting arguments of a call that never occurs is contradictory.","If the call should happen, fix the SUT path (guard clause, exception, wiring) that prevents it.","Prefer expects($this->atLeastOnce()) over any() so a never-called method fails with a clear count message instead of this one."],"exampleFix":"// before\n$api->expects($this->any())->method('fetch')->with('/users');\n$service->listUsers(); // uses a cached path, fetch() never called\n\n// after: assert the interaction explicitly (or drop the stale expectation)\n$api->expects($this->atLeastOnce())->method('fetch')->with('/users');\n$service->listUsers(forceRefresh: true);","handlingStrategy":"validation","validationCode":"// Ensure the interaction happens before parameter verification matters:\n// pair with() with atLeastOnce() so a never-called method fails with a clear\n// count error rather than the misleading 'Doubled method does not exist.'\n$mock->expects($this->atLeastOnce())->method('foo')->with(1);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never use expects(any()) with with() on a method that might not be called — verify it first with atLeastOnce().","Treat this message as 'method never invoked', not as a mocking-generator problem; check wiring and call path first.","Remove with() constraints when the expectation is removed; stale parameter rules fire at verification time.","Assert the call path with a return-value assertion before asserting its arguments."],"tags":["phpunit","mock","never-invoked","with-constraints","misleading-message"],"backgroundTag":"mock-verification-without-invocation","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}