1
votes

I am using the mockery to test a method that make a lot of doctrine repository invocations with different repositories. This is the method that i set up all my repository mocks:

public function testService()
{
    $mockDoctrine = $this->getMockDoctrine();
    $mockDoctrine->shouldReceive('getRepository')->once()
        ->andReturn($this->getRepositoryAMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->andReturn($this->getRepositoryBMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->andReturn($this->getRepositoryCMock());

    //here is where i hit my test
    $products = $this->service->fire(1, 1);

    $this->assertInstanceOf('Illuminate\Support\Collection', $products);
    foreach ($products as $v) {
        $this->assertInstanceOf('Illuminate\Support\Collection', $v);
    }
}

This is the method that i mock the Doctrine:

public function getMockDoctrine()
{
    $mockDoctrine = \App::make('Doctrine');
    $mockDoctrine->shouldReceive('persist')
        ->andReturn(true);
    $mockDoctrine->shouldReceive('flush')
        ->andReturn(true);

    return $mockDoctrine;
}

These are my repositories mock

public function getRepositoryAMock()
{
    $repository = \Mockery::mock('MyARepository');
    $repository->shouldReceive('findBy')
        ->with(['paramA' => 1, 'paramB' => 1])
        ->andReturn($this->getMockA());

    return $repository;
}

public function getRepositoryBMock()
{
    $repository = \Mockery::mock('MyBRepository');
    $repository->shouldReceive('findById')
        ->with(1)
        ->andReturn($this->getMockA());

    return $repository;
}

public function getRepositoryCMock()
{
    $repository = \Mockery::mock('MyCRepository');
    $repository->shouldReceive('findOneBy')
        ->with(['paramA' => 1, 'paramB' => 1])
        ->andReturn($this->getMockA());

    return $repository;
}

This is where in fact i set the return of my mock

public function getMockA()
{
    $obj = new MyClass();
    $reflection = new \ReflectionClass($obj);
    $id = $reflection->getProperty('id');
    $id->setAccessible(true);
    $id->setValue($obj, 1);
    $obj
        ->setLogin('foo')
        ->setPassword('bar')
        ->setCode(1);

    return $obj;
}

And then i receive an error like this:

1) MyClassTest::testService BadMethodCallException: Method Mockery_2_ClassBRepository::findOneBy() does not exist on this mock object

Assuming that i have 3 methods with repositories being called in testService() method, the method that mockery is not finding is in the third one, but mockery thinks it is in the second, so obviously he won't find, because in the second one, does not exist the "findOneBy()" doctrine method just in the third.

How can i solve this ?

2

2 Answers

1
votes

You should be able to use mockery's with().
For example:

$mockDoctrine
    ->shouldReceive('getRepository')
    ->with('MyAReposiotry')->once()
    ->andReturn($this->getRepositoryAMock());

And like that for every repository (with different value in with).

But I would rather inject repositories in that service instead of getting it from entity manager inside service. It is way better for testing. Take a look at this blog post.

0
votes

Thanks to Mr Ivan,

Now my method is working.

In my real class, i was getting the repository with the entity class,
like:

 Doctrine::getRepository('MyEntityClassA')
        ->findBy(['paramA' => 1, 'paramB' => 1]);

so i changed my test method to use the "with" passing the entity class:

public function testService()
{
    $mockDoctrine = $this->getMockDoctrine();
    $mockDoctrine->shouldReceive('getRepository')
        ->with('MyEntityClassA')->once()
        ->andReturn($this->getRepositoryAMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->with('MyEntityClassB')->once()
        ->andReturn($this->getRepositoryBMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->with('MyEntityClassC')->once()
        ->andReturn($this->getRepositoryCMock());

    //here is where i hit my test
    $products = $this->service->fire(1, 1);

    $this->assertInstanceOf('Illuminate\Support\Collection', $products);
    foreach ($products as $v) {
        $this->assertInstanceOf('Illuminate\Support\Collection', $v);
    }
}