跳到内容

如何测试 Doctrine 仓库

编辑此页

另请参阅

主要测试指南 介绍了如何在自动化测试中使用和设置数据库。本文内容展示了测试 Doctrine 仓库的方法。

在单元测试中 Mock Doctrine 仓库

不建议对 Doctrine 仓库进行单元测试。仓库应该针对真实的数据库连接进行测试。但是,如果您仍然需要这样做,请查看以下示例。

假设您要测试的类如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/Salary/SalaryCalculator.php
namespace App\Salary;

use App\Entity\Employee;
use Doctrine\ORM\EntityManager;

class SalaryCalculator
{
    public function __construct(
        private EntityManager $entityManager,
    ) {
    }

    public function calculateTotalSalary(int $id): int
    {
        $employeeRepository = $this->entityManager
            ->getRepository(Employee::class);
        $employee = $employeeRepository->find($id);

        return $employee->getSalary() + $employee->getBonus();
    }
}

由于 EntityManagerInterface 通过构造函数注入到类中,您可以在测试中传递一个 mock 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// tests/Salary/SalaryCalculatorTest.php
namespace App\Tests\Salary;

use App\Entity\Employee;
use App\Salary\SalaryCalculator;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use PHPUnit\Framework\TestCase;

class SalaryCalculatorTest extends TestCase
{
    public function testCalculateTotalSalary(): void
    {
        $employee = new Employee();
        $employee->setSalary(1000);
        $employee->setBonus(1100);

        // Now, mock the repository so it returns the mock of the employee
        $employeeRepository = $this->createMock(EntityRepository::class);
        $employeeRepository->expects($this->any())
            ->method('find')
            ->willReturn($employee);

        // Last, mock the EntityManager to return the mock of the repository
        // (this is not needed if the class being tested injects the
        // repository it uses instead of the entire entity manager)
        $entityManager = $this->createMock(EntityManager::class);
        $entityManager->expects($this->any())
            ->method('getRepository')
            ->willReturn($employeeRepository);

        $salaryCalculator = new SalaryCalculator($entityManager);
        $this->assertEquals(2100, $salaryCalculator->calculateTotalSalary(1));
    }
}

在本例中,您是从内向外构建 mocks,首先创建 employee,它由 Repository 返回,而 Repository 本身又由 EntityManager 返回。这样,测试中不涉及任何真实的类。

Doctrine 仓库的功能测试

功能测试 中,您将使用实际的 Doctrine 仓库向数据库发出查询,而不是 mock 它们。为此,请通过服务容器获取实体管理器,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// tests/Repository/ProductRepositoryTest.php
namespace App\Tests\Repository;

use App\Entity\Product;
use Doctrine\ORM\EntityManager;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class ProductRepositoryTest extends KernelTestCase
{
    private ?EntityManager $entityManager;

    protected function setUp(): void
    {
        $kernel = self::bootKernel();

        $this->entityManager = $kernel->getContainer()
            ->get('doctrine')
            ->getManager();
    }

    public function testSearchByName(): void
    {
        $product = $this->entityManager
            ->getRepository(Product::class)
            ->findOneBy(['name' => 'Priceless widget'])
        ;

        $this->assertSame(14.50, $product->getPrice());
    }

    protected function tearDown(): void
    {
        parent::tearDown();

        // doing this is recommended to avoid memory leaks
        $this->entityManager->close();
        $this->entityManager = null;
    }
}
这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可证获得许可。
目录
    版本