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
Gaurav
  • 191
  • 18
  • 1
    Don't mock third party code. It has been already explained thousands of times already. For example here: https://stackoverflow.com/a/29471209/330267 Technology might be different but the same rules apply. – Jakub Zalas Jun 27 '17 at 17:13
  • @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.** – Gaurav Jun 28 '17 at 01:57

2 Answers2

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')
    // ...
colburton
  • 4,685
  • 2
  • 26
  • 39
  • I am not sure how I can do it. Could you please help me? Here's the link to my repository. https://github.com/gaurav-garry/friend-follower-bundle – Gaurav Jul 04 '17 at 03:04
  • 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:43 – Gaurav Jul 04 '17 at 03:09
  • @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. – colburton Jul 04 '17 at 06:31
  • Hi Colburton, Did you check the repo link I sent you? That's the updated code. I already got rid of that method. – Gaurav Jul 05 '17 at 05:17
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));
Alessandro Minoccheri
  • 35,521
  • 22
  • 122
  • 171
  • 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:305 – Gaurav Jun 27 '17 at 14:37
  • update answer try now, but I think you will get more mock – Alessandro Minoccheri Jun 27 '17 at 14:49