Reputation: 2814
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
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