Skip to content

Instantly share code, notes, and snippets.

@havvg
Created June 1, 2012 14:22
Show Gist options
  • Save havvg/2852498 to your computer and use it in GitHub Desktop.
Save havvg/2852498 to your computer and use it in GitHub Desktop.
PHPUnit mock Interface extending Iterator
<?php
namespace Ormigo\Tests;
abstract class AbstractTest extends \PHPUnit_Framework_TestCase
{
/**
* Apply expectations for an \Iterator on a mock object.
*
* @see http://php.net/Iterator
*
* @param object $mock A mock object to apply expectations to.
* @param array $content The content the mock will contain and return while iteraring.
* @param bool $withKey Whether to add expectations on the key of the iterator.
* Set this to true if you expect a key based loop:
* foreach ($foo as $key => $value)
* @param int $counter The method invocation start counter.
* This parameter should be altered when using additional
* expectations before the actual iteration.
*
* @return int The next method invocation counter to add further expectations.
*/
public function expectIterator($mock, array $content, $withKey = false, $counter = 0)
{
$mock
->expects($this->at($counter))
->method('rewind')
;
foreach ($content as $key => $value) {
$mock
->expects($this->at(++$counter))
->method('valid')
->will($this->returnValue(true))
;
$mock
->expects($this->at(++$counter))
->method('current')
->will($this->returnValue($value))
;
if ($withKey) {
$mock
->expects($this->at(++$counter))
->method('key')
->will($this->returnValue($key))
;
}
$mock
->expects($this->at(++$counter))
->method('next')
;
}
$mock
->expects($this->at(++$counter))
->method('valid')
->will($this->returnValue(false))
;
return ++$counter;
}
}
<?php
// The returned counter allows such usage ..
$applicableSenders = $this->getSenderCollectionMock();
$counter = $this->expectIterator($applicableSenders, array($senderA, $senderB));
$this->expectIterator($applicableSenders, array($senderA, $senderB), false, $counter);
// .. or simply nest them
$applicableSenders = $this->getSenderCollectionMock();
$this->expectIterator($applicableSenders, array($senderA, $senderB), false,
$this->expectIterator($applicableSenders, array($senderA, $senderB))
);
// It helps to test e.g. nested foreach
// assume $parties contains two entries ..
foreach ($parties as $eachInterestedParty) {
// .. then this iteration will be called twice!
foreach ($applicableSender as $eachSender) {
// $eachSender is $senderA and $senderB respectively
}
}
// You can also apply calls right before the Iterator ..
$senders
->expects($this->at(0))
->method('before')
;
$counter = $this->expectIterator($senders, array($senderA, $senderB), false, 1);
// .. in between ..
$senders
->expects($this->at($counter))
->method('between')
;
$counter = $this->expectIterator($senders, array($senderA, $senderB), false, ++$counter);
// .. and afterwards.
$senders
->expects($this->at($counter))
->method('after')
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment