I have a custom entity repository. For example, it looks like this:
namespace Foo\Repository;
use Doctrine\ORM\EntityRepository;
class Article extends EntityRepository
{
public function findRecent($limit)
{
$qb = $this->createQueryBuilder('a');
$qb->andWhere('a.publishDate IS NOT NULL')
->orderBy('a.publishDate', 'DESC')
->setMaxResults($limit);
return $qb->getQuery()->getResult();
}
}
I want to test in this case:
- There is an ORDER BY in "recent"
- There is a limit
- The entity must have a publish date
I do not want to validate the SQL output of the query builder, since Doctrine can change the SQL between different versions. That will break my unit test. Therefore, my idea was this:
- Create a mock of my repository
- Create a mock of the query builder
- Make sure
$this->createQueryBuilder('a')returns the mocked query builder - Test for method calls on the query builder
In code:
namespace FooTest\Repository;
use PHPUnit_Framework_TestCase as TestCase;
class ArticleRepositoryTest extends TestCase
{
protected $qb;
protected $repository;
public function setUp()
{
$this->qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder')
->disableOriginalConstructor()
->getMock();
$this->repository = $this->getMockBuilder('Foo\Repository\Article')
->disableOriginalConstructor()
->getMock();
$this->repository->expects($this->once())
->method('createQueryBuilder')
->with($this->equalTo('a'))
->will($this->returnValue($this->qb));
}
public function testFindRecentLimitsToGivenLimit()
{
$limit = '1';
$this->qb->expects($this->any())
->method('setMaxResults')
->with($this->equalTo($limit));
$this->repository->findRecent($limit);
}
public function testFindRecentOrdersByPublishDate()
{
$this->qb->expects($this->any())
->method('andWhere')
->with($this->equalTo('a.publishDate'), $this->equalTo('DESC'));
$this->repository->findRecent(1);
}
}
This findRecent() call however never calls createQueryBuilder internally. PhpUnit points out:
FooTest\Repository\ArticleRepositoryTest::testFindRecentLimitsToGivenLimit Expectation failed for method name is equal to when invoked 1 time(s). Method was expected to be called 1 times, actually called 0 times.
I think I did something wrong in creating the repository mock. How can I make sure this approach works? Or if there is a better alternative, what is that?