Search code examples
phpunit-testingdoctrine-ormmockery

Can I combine shouldReceive and shouldNotReceive in Mockery for a Controller Test in ZF2 with Doctrine Entity Manager?


I'm currently working on a ZF2/Doctrine project and I am trying to get my PHPUnit suite up and running. First time trying to write unit tests for a ZF2 project, a Doctrine project and also first time working with Mockery. So far so good, but I encounter a problem with the Doctrine EntityManager;

I just mocked my Doctrine\Orm\EntityManager and I want a getRepository call with a certain parameter return a mocked repository, but I want the calls to other repositories stay the same. I assumed that using a shouldReceive and shouldNotReceive alongside each other would work, but somehow I keep getting errors;

class ProductControllerTest extends AbstractHttpControllerTestCase
{
    public function testViewAction()
    {
        $serviceLocator = $this->getApplicationServiceLocator();
        $entityManager = \Mockery::mock($serviceLocator->get('Doctrine\ORM\EntityManager'));

        $entityManager
           ->shouldReceive('getRepository')
           ->with('App\Entity\Product')
           ->andReturn(\Mockery::mock('App\Repository\Product'));

        $entityManager
           ->shouldNotReceive('getRepository')
           ->with(\Mockery::not('App\Entity\Product'));

        $serviceLocator
            ->setAllowOverride(true)
            ->setService('Doctrine\ORM\EntityManager', $entityManager);

        $this->dispatch('/products/first-product');

        $this->assertResponseStatusCode(200);
    }
}

The reason I want this particular thing is because I just want to write a test for this piece of code. Some underlying code isn't perfect, so please help me focussing on this part, but I want to have the ability to refactor underlying pieces of code without my application breaking. Have to start somewhere making my application totally testable ;)

But is there something in my logic that is flawed or am I missing something? Many thanks!


Solution

  • You can try something like this. The idea is to first setup a default expectation using byDefault() and than define your specific expectations, which will be preferred over the default ones.

    $entityManager
        ->shouldReceive('getRepository')
        ->with(\Mockery::any())
        ->andReturn(\Mockery::mock('Doctrine\ORM\EntityRepository'))
        ->byDefault();
    
    $entityManager
        ->shouldReceive('getRepository')
        ->with('App\Entity\Product')
        ->andReturn(\Mockery::mock('App\Repository\Product'));