How to get UnitOfWork from EventManager Mock Object Or how to get last persisted object in PHP Unit?
Asked Answered
D

2

6

I am trying to unit test my bundle and I want to get unit of work from EventManager Mock. Basically, I want to get the last persisted object. I know in normal application, I can do the same with a EventSubscriber.

What I want to achieve is basically, check status of previous persisted record if its flag is pending, then in next persist, I want to update it to not pending.

Example:

Here's how I get Event Manager:

/**
 * @param Entity\Friend|null $friendEntity
 * @return \Doctrine\ORM\EntityManager|\PHPUnit_Framework_MockObject_MockObject
 */
private function getEntityManager(Entity\Friend $friendEntity = null)
{
    $repository = $this
        ->getMockBuilder('\Doctrine\ORM\EntityRepository')
        ->disableOriginalConstructor()
        ->setMethods(['findBy'])
        ->getMock();
    $repository
        ->expects($this->any())
        ->method('findBy')
        ->will($this->returnValue(null));

    /** @var \Doctrine\ORM\EntityManager|\PHPUnit_Framework_MockObject_MockObject $entityManager */
    $entityManager = $this
        ->getMockBuilder('\Doctrine\ORM\EntityManager')
        ->setMethods(['getRepository', 'getUnitOfWork', 'persist'])
        ->disableOriginalConstructor()
        ->getMock();
    $entityManager
        ->expects($this->any())
        ->method('getRepository')
        ->will($this->returnValue($repository));
    $entityManager
        ->expects($this->any())
        ->method('getUnitOfWork')
        ->will($this->returnValue($repository));
    $entityManager
        ->expects($this->any())
        ->method('persist')
        ->with($friendEntity)
        ->will($this->returnValue(null));
    return $entityManager;
}

And in my test:

/**
 * Test add friend when friend pending
 */
public function testAddFriendPending()
{
    $friendEntity = new Entity\Friend($this->friend, $this->user);
    $entityManager = $this->getEntityManager($friendEntity);
    $pendingRequest = new FriendService($entityManager);
    /** @var Entity\Friend $lastInsert */
    $lastInsert = $pendingRequest->addFriend($this->friend, $this->user);
    $lastInsert->setId(1);
    $friendAddRequest = new FriendService($entityManager);
    $friendAddRequest->addFriend($this->user, $this->friend);
    $response = $friendAddRequest->getStatus();
    $this->assertEquals(Entity\Friend::FRIEND_ADD_STATUS_COMPLETED, $response);
}

EDIT

Still receiving errors:

vendor/phpunit/phpunit/phpunit src/NalabTnahsarp/FriendFollowerBundle/Tests/Service/
PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

EE                                                                  2 / 2 (100%)

Time: 102 ms, Memory: 4.00MB

There were 2 errors:

1) NalabTnahsarp\FriendFollowerBundle\Tests\Service\FriendTest::testAddFriendNotPending
Error: Call to a member function getUnitOfWork() on null

/Users/Sites/app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:194
/Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Service/Friend.php:140
/Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Service/Friend.php:63
/Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Tests/Service/FriendTest.php:43

2) NalabTnahsarp\FriendFollowerBundle\Tests\Service\FriendTest::testAddFriendPending
Error: Call to a member function getUnitOfWork() on null

/Users/Sites/app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:194
/Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Service/Friend.php:140
/Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Service/Friend.php:63
/Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Tests/Service/FriendTest.php:57
Discobolus answered 27/6, 2017 at 14:16 Comment(2)
Don't mock third party code. It has been already explained thousands of times already. For example here: https://mcmap.net/q/1916422/-mocking-entitymanager Technology might be different but the same rules apply.Fowle
@JakubZalas, so you mean I should not do a unit test, instead do a functional test? I would have loved to have an in-memory check for the code instead of involving a test database. As this library I want to share with community and dont expect them to install a database to perform testing.Discobolus
A
2

I suppose you want to check that the persisted entity has some specific values set and of course is the right type.

You should add this to the persist method for the entity manager like this:

If persist() is only called once you have it easy:

$entityManager
    ->expects($this->once())
    ->method('persist')
    ->with($theEntityYouExpectWithAllValues)
    ->will($this->returnValue(null));

With more sophisticated expectations:

$entityManager
    ->expects($this->once())
    ->method('persist')
    ->willReturnCallback(function($entityToTest){
        $this->assertInstanceOf(EntityClass::class, $entityToTest);
        $this->assertEquals('some_value', $entityToTest->someKey);
    });

If it is not the only call to persist() in the tested code you have to use $this->at() instead of once():

$entityManager
    ->expects($this->at(3)) // 3rd call of any method on manager not just persist
    ->method('persist')
    // ...
Aware answered 3/7, 2017 at 19:47 Comment(4)
I am not sure how I can do it. Could you please help me? Here's the link to my repository. github.com/gaurav-garry/friend-follower-bundleDiscobolus
I still receive the following errors: There were 2 errors: 1) NalabTnahsarp\FriendFollowerBundle\Tests\Service\FriendTest::testAddFriendNotPending Error: Call to a member function getUnitOfWork() on null /Users/Sites/app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:194 /Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Service/Friend.php:140 /Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Service/Friend.php:63 /Users/Sites/app/src/NalabTnahsarp/FriendFollowerBundle/Tests/Service/FriendTest.php:43Discobolus
@Gaurav: With this you do not need getLastPersistedEntity() anymore. This method ist producing your error. Don't call it, my proposal already does the checks to the entity you want.Aware
Hi Colburton, Did you check the repo link I sent you? That's the updated code. I already got rid of that method.Discobolus
P
0

try to add another expected method to use that function like this:

    $configurationMock = $this
        ->getMockBuilder('\Doctrine\ORM\Mapping\EntityListenerResolver')
        ->disableOriginalConstructor()
        ->getMock();

    $entityManager
        ->expects($this->any())
        ->method('getConfiguration')
        ->will($this->returnValue($configurationMock));
Pemba answered 27/6, 2017 at 14:27 Comment(2)
Tests\Service\FriendTest::testAddFriendPending BadMethodCallException: Undefined method 'getEntityListenerResolver'. The method name must start with either findBy or findOneBy! /Users/Sites/app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:226 /Users/Sites/app/vendor/doctrine/orm/lib/Doctrine/ORM/Event/ListenersInvoker.php:59 /Users/Sites/app/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:305Discobolus
update answer try now, but I think you will get more mockPemba

© 2022 - 2024 — McMap. All rights reserved.