How to mock a method from a class that you are testing with Prophecy?

I want to use Prophecy ("phpspec / prophecy-phpunit") for the first time to create unit tests for my classes. I want to test a function that calls another function in the same service, here is the code:

class UserManager { private $em; private $passwordHelper; public function __construct(\Doctrine\ORM\EntityManager $em, \MainBundle\Helper\PasswordHelper $passwordHelper) { $this->em = $em; $this->passwordHelper = $passwordHelper; } public function getUserForLdapLogin($ldapUser) { $dbUser = $this ->em ->getRepository('MainBundle:User') ->findOneBy(array('username' => $ldapUser->getUsername())); return (!$dbUser) ? $this->createUserFromLdap($ldapUser) : $this->updateUserFromLdap($ldapUser, $dbUser); } 

The first problem I ran into was that I used findOneByUsername , and Prophecy, as far as I know, does not allow: mock magic methods ( _call for EntityRepository ), false methods that do not exist, scoff at the class you are testing . If this is true, I have a little pickle, that is, I can not check this function without testing other functions in the class.

So far, my test is as follows:

 class UserManagerTest extends \Prophecy\PhpUnit\ProphecyTestCase { public function testGetUserForLdapLoginWithNoUser() { $ldapUser = new LdapUser(); $ldapUser->setUsername('username'); $em = $this->prophesize('Doctrine\ORM\EntityManager'); $passwordHelper = $this->prophesize('MainBundle\Helper\PasswordHelper'); $repository = $this->prophesize('Doctrine\ORM\EntityRepository'); $em->getRepository('MainBundle:User')->willReturn($repository); $repository->findOneBy(array('username' => 'username'))->willReturn(null); $em->getRepository('MainBundle:User')->shouldBeCalled(); $repository->findOneBy(array('username' => 'username'))->shouldBeCalled(); $service = $this->prophesize('MainBundle\Helper\UserManager') ->willBeConstructedWith(array($em->reveal(), $passwordHelper->reveal())); $service->reveal(); $service->getUserForLdapLogin($ldapUser); } } 

And, of course, the tests fail because promises on $em and the repository fails. If I create an instance of the class that I am testing, the tests fail because the function then calls createUserFromLdap() in the same class and is not being tested.

Any suggestions?

+5
source share
3 answers

First problem:

Do not use magic, magic is evil. __call can lead to unpredictable behavior.

"promises on $ em and the repository fails":

Do not make your code depend on the class, but on the interface. Then mock the interface instead of the class! You should make fun of the ObjectManager instead of the EntityManager. (do not forget to change the type of parameters)

And the last one:

Before disclosure.

 $service->createUserFromLdap() ->shouldBeCalled() ->willReturn(null); 
0
source

As for your problem of not being able to mock methods that don't exist, you can use

http://docs.mockery.io/en/latest/

instead of prophecy. Bullying allows you to do just that. Strictly speaking, this violates some of the rules of good design, but on the other hand, sometimes it is very useful. In any case, the mockery is very similar as the functions go, and equally it is intuitive and easy to use imo. However, they still haven't released a stable version, so just keep in mind that if you decide to use it.

Here you can find a good comparison of the two libraries.

http://everzet.com/post/72910908762/conceptual-difference-between-mockery-and-prophecy

0
source

What you are trying to achieve is a partial layout that is not supported by Prophecy. Read more about this here https://github.com/phpspec/prophecy/issues/101 and https://github.com/phpspec/prophecy/issues/61 .

TL DR; Create your classes with a single responsibility, so you donโ€™t have to mock other functions.

0
source

Source: https://habr.com/ru/post/1211594/


All Articles