A strict version of willReturnMap()
Currently, if a values map for a method mocked with willReturnMap() does not have the parameters received, it will simply return null. When writing tests for complex code, it's not always clear which inputs weren't present? and it gets even more confusing if null is a valid return value.
I therefore propose to have an option to explode in an obvious way if inputs were not found. Possible ways to do that could be a second parameter to willReturnMap(): bool $failIfMissing or another function, willReturnMapOrFail(). The failure message would need to report the parameters to the mocked method.
I did experience the same problem while migrating away from ->at() and trying to use willReturnMap in a few places. The most confusing IMO is that you have say:
function foo(bool $a, string $b = null, int $c = 5): ?string {}
And it is only ever called like ->foo(true); and ->foo(false);, relying on the default values for the other parameters.
Then you mock it with:
$mock
->expects($this->any())
->method('foo')
->willReturnMap(
[true, "bla"],
[false, "blop"]
);
Then it will just return null because it expects a map like this:
->willReturnMap(
[true, null, 5, "bla"],
[false, null, 5, "blop"]
);
Not only is this fairly unexpected to me (and undocumented, but the code is easy to read https://github.com/sebastianbergmann/phpunit/blob/master/src/Framework/MockObject/Stub/ReturnValueMap.php), it is very brittle IMO as adding any new optional arg to a method will silently break all return maps you have in tests, they'll start returning null and that may or may not break tests depending on how the code and tests are written (surely it should break the tests).
Similarly when writing tests, if the code or tests aren't up to par but somehow things function with a null return value, you may be tricked in a false sense of confidence that things are tested and pass even though the tests are testing nothing.
BTW related issue in https://github.com/sebastianbergmann/phpunit/issues/3999
Same problem here. It is very unintuitive that one has to pass null's to the return map for default parameters that are not used in the tested code.