Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit mocking - fail immediately when method called x times

With PHPUnit, I am testing a sequence of method calls using ->at(), like so:

$mock->expects($this->at(0))->method('execute')->will($this->returnValue('foo'));
$mock->expects($this->at(1))->method('execute')->will($this->returnValue('bar'));
$mock->expects($this->at(2))->method('execute')->will($this->returnValue('baz'));

How can I set up the mock so that, in the above scenario, if execute() is called four or more times, it will immediately fail? I tried this:

$mock->expects($this->at(3))->method('execute')->will($this->throwException(new Exception('Called too many times.')));

But this also fails if execute() is not called four times. It needs to fail immediately, otherwise the system under test will produce errors of its own, which causes the resulting error message to be unclear.

like image 541
ezzatron Avatar asked Dec 07 '22 21:12

ezzatron


1 Answers

I managed to find a solution in the end. I used a comination of $this->returnCallback() and passing the PHPUnit matcher to keep track of the invocation count. You can then throw a PHPUnit exception so that you get nice output too:

$matcher = $this->any();
$mock
    ->expects($matcher)
    ->method('execute')
    ->will($this->returnCallback(function() use($matcher) {
        switch ($matcher->getInvocationCount())
        {
            case 0: return 'foo';
            case 1: return 'bar';
            case 2: return 'baz';
        }

        throw new PHPUnit_Framework_ExpectationFailedException('Called too many times.');
    }))
;
like image 107
ezzatron Avatar answered Dec 10 '22 11:12

ezzatron