如何对 createQueryBuilder 进行单元测试
How to unit test createQueryBuilder
我有这个方法:
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();
}
我正在尝试以这种方式进行测试(显然不是正确的):
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));
}
我得到的错误:
1)
App\Tests\Unit\Infrastructure\Domain\Model\Product\DoctrineProductRepositoryTest::testFindAllProductsByFilters
Error: Call to a member function from() on null
这段代码甚至可以通过单元测试进行测试吗?
你应该not mock what you don't own,我的建议是避免在这种情况下进行单元测试。
此外,我不会使用(滥用)模拟(通常是测试替身),因为您正在测试实现而不是 SUT 的行为。
让我们看一个例子
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
}
}
当然,这是故意设计的一个微不足道的例子。如果你在 Bar
测试中使用测试替身,你会写类似`
$fooMock->expects($this->once())
->method('doSomething')
->willReturn(1);
假设 Foo
将其更改为 public API,将 doSomething
重命名为 doSomethingElse
。发生什么了?即使 Foo
行为根本没有改变,您也需要更改测试。
如前所述,这是一个微不足道的例子,但应该会给你一个想法。
我有这个方法:
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();
}
我正在尝试以这种方式进行测试(显然不是正确的):
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));
}
我得到的错误: 1)
App\Tests\Unit\Infrastructure\Domain\Model\Product\DoctrineProductRepositoryTest::testFindAllProductsByFilters Error: Call to a member function from() on null
这段代码甚至可以通过单元测试进行测试吗?
你应该not mock what you don't own,我的建议是避免在这种情况下进行单元测试。 此外,我不会使用(滥用)模拟(通常是测试替身),因为您正在测试实现而不是 SUT 的行为。
让我们看一个例子
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
}
}
当然,这是故意设计的一个微不足道的例子。如果你在 Bar
测试中使用测试替身,你会写类似`
$fooMock->expects($this->once())
->method('doSomething')
->willReturn(1);
假设 Foo
将其更改为 public API,将 doSomething
重命名为 doSomethingElse
。发生什么了?即使 Foo
行为根本没有改变,您也需要更改测试。
如前所述,这是一个微不足道的例子,但应该会给你一个想法。