I have this method:
public function findAllBy(?string $categoryId): array
{
$qb = $this->entityManager->createQueryBuilder()
->select('p')
->from(Product::class, 'p');
if (null !== $categoryId) {
$qb->from(Category::class, 'cc')
->join(CategoryProduct::class, 'cp', Join::WITH, 'p.id = cp.product_id')
->join(Category::class, 'c', Join::WITH, 'cp.category_id = c.id')
->where('cc.id = :id')
->andWhere('cc.left <= c.left')
->andWhere('cc.right >= c.right')
->setParameter('id', $categoryId, 'uuid');
}
return $qb->getQuery()->getResult();
}
I am trying to test it this way ( obviously not the correct one ):
public function testFindAllProductsByFilters():void
{
$entityRepositoryMock = $this->createMock(EntityRepository::class);
$entityManagerMock = $this->createMock(EntityManagerInterface::class);
$entityManagerMock->expects($this->once())
->method('getRepository')
->with(Product::class)
->willReturn($entityRepositoryMock);
$entityManagerMock->expects($this->once())
->method('createQueryBuilder')
->willReturn($entityRepositoryMock);
$this->repository = new DoctrineProductRepository($entityManagerMock);
$this->assertIsArray($this->repository->findAllBy(ProductFactory::CATEGORY_ID_FIRST));
}
The error I get: 1)
App\Tests\Unit\Infrastructure\Domain\Model\Product\DoctrineProductRepositoryTest::testFindAllProductsByFilters Error: Call to a member function from() on null
Is this piece of code even testable by Unit Test ?
CodePudding user response:
As you should not mock what you don't own, my suggestion is to avoid unit tests in this kind of scenarios. Moreover I would not use (abuse) a mock (a test double in general) as you're testing the implementation and not the behaviour of your SUT.
Let's see an example
class Foo()
{
public function doSomething(): int
{
// some heavy logic here
}
}
class Bar()
{
public function doSomething(Foo $foo): int
{
$result = $foo->doSomething();
// other elaboration upon $result
}
}
That's a deliberately trivial example of course. If you use a test double in Bar
test, you would write something like`
$fooMock->expects($this->once())
->method('doSomething')
->willReturn(1);
Let's say that Foo
changes it's public API, renaming doSomething
to doSomethingElse
. What happens? You need to change the test aswell even if Foo
behaviour didn't changed at all.
As said before it's a trivial example but should give you an idea.