PHPUnit mocking - crash immediately when a method is called x times

With PHPUnit, I test the sequence of method calls using β†’ at (), for example:

$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 customize the layout, so that in the case described above, 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. He must immediately otherwise, the system under test will create its own errors, which will lead to an unclear error message.

+4
source share
4 answers

I managed to find a solution at the end. I used the compilation of $this->returnCallback() and passed a PHPUnit socket to keep track of the call counter. Then you can throw a PHPUnit exception to get a good result:

 $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.'); })) ; 
+9
source

In special cases like this, I usually use something like the following:

 public function myMockCallback() { ++$this -> _myCounter; if( $this -> _myCounter > 3 ) { // THROW EXCEPTION OR TRIGGER ERROR } ... THEN YOUR CASE STATEMENT OR IF/ELSE WITH YOUR CHOICE OF RETURN VALUES } ... INSIDE TEST FUNCTION .... $mockObject ->expects($this->any()) ->method('myMethod') ->will($this->returnCallback( array ($this, 'myMockCallback' ))); 
+3
source

You can split the test into 2 dependent methods using @depend .

In this case, your first test only checks the exact 3 execution methods, and the second one checks the other logic.

+2
source

How about using data providers ?

 class MyTest extends PHPUnit.... { /** * @var const how much till throwing exception */ const MAX_EXECUTE_TILL_EXCEPTION = 3; public function setUp(){} public function tearDown(){} /** * @dataProvider MyExecuteProvider */ pulbic function testMyExecuteReturnFalse($data){ $mock = //setup your mock here //if using "$ret" doesn't work you cant just call another private helper that will decide if you need to // return value or throwing exception if (self::MAX_EXECUTE_TILL_EXCEPTION == $data){ $ret = $this->throwException(new Exception('Called too many times.')); } else { $ret = $this->returnValue('foo'); } $mock->expects($this->at($data))->method('execute')->will($ret); } public function MyExecuteProvider(){ return array( 0,1,2,3 ) } } 

This is just another idea, and I think that zerkms also offered a very good idea.

0
source

All Articles