Greg.Forbes
Greg.Forbes

Reputation: 2814

How do I mock the Doctrine PersistentCollection in PHPUnit

Does anyone know how to mock a Doctrine PersistentCollection?

When I try and mock the class directly using PHPUnit and Mockery I get an exception that reads:

Mockery\Exception: The class Doctrine\ORM\PersistentCollection is marked final a

nd its methods cannot be replaced. Classes marked final can be passed in to \Moc kery::mock() as instantiated objects to create a partial mock, but only if the m ock is not subject to type hinting checks.

My research indicates that Mockery and/or phpUnit cannot use reflection once the methods are marked as final.

I then tried to create a stdClass and give it the methods an iterator would use (valid/current/next) but a foreach loop will not call these unless the class implements an iterator.

Thus, the following code does not work...

$this -> collectionMock = \Mockery::mock('PersistentCollection, Traversable');
$this -> collectionMock -> shouldReceive('rewind');
$this -> collectionMock -> shouldReceive('valid') -> andReturn('true');
$this -> collectionMock -> shouldReceive('next');
$this -> collectionMock -> shouldReceive('current') ->andReturn();

And throws seems to throw the following fatal error:

Fatal error: Cannot redeclare Mockery_1670979900_PersistentCollection_Traversable::rewind() 
in C:\zendProject\zf2\vendor\mockery\mockery\library\Mockery\Generator.php(129) :
eval()'d code on line 43

Has anyone come up with a good way to mock this class

Upvotes: 4

Views: 2990

Answers (1)

Jeremy Kendall
Jeremy Kendall

Reputation: 2869

I doesn't seem like it's possible to mock a class that's been declared final. There may be some hope, however. Since PersistentCollection implements both Doctrine\Common\Collections\Collection and Doctrine\Common\Collections\Selectable, you can use Mockery to mock an object implementing both interfaces.

Mockery::mock(
    'Doctrine\Common\Collections\Collection, Doctrine\Common\Collections\Selectable'
);

I've used this to good effect in one of my own projects.

As to why you can't mock a final class, this is the best I could find:

Mockery

The ability to mock final classes with Mockery is limited:

Again, the primary purpose is to ensure the mock object inherits a specific type for type hinting. There is an exception in that classes marked final, or with methods marked final, cannot be mocked fully. In these cases a partial mock (explained later) must be utilised.

$mock = \Mockery::mock('alias:MyNamespace\MyClass');

Search the linked page for 'final'. You'll find all the documentation I could find.

PHPUnit

Attempting to mock a final class in PHPUnit throws an exception by design.

Upvotes: 3

Related Questions