Как тестировать хранилище Doctrine
Дата обновления перевода 2024-07-29
Как тестировать хранилище Doctrine
See also
В главном руководстве по тестированию описано, как использовать и настраивать базу данных для ваших автоматизированных тестов. Содержание данной статьи показывает способы тестирования хранилищ Doctrine.
Имитация хранилища Doctrine в модульных тестах
Модульное тестирование хранилищ Doctrine не рекомендуется. Хранилища предназначены для тестирования на реальном соединении с базой данных. Однако, если вам все же необходимо это сделать, рассмотрите следующий пример.
// src/Salary/SalaryCalculator.php namespace AppSalary;
use AppEntityEmployee; use DoctrineORMEntityManager;
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
внедряется в класс через конструктор, то
очень легко передать объект-макет в пределах теста:
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);
// Теперь, сымитируйте хранилише, чтобы оно возвращало имитацию работника
$employeeRepository = $this->createMock(EntityRepository::class);
$employeeRepository->expects($this->any())
->method('find')
->willReturn($employee);
// Наконец, сымитируйте EntityManager, чтобы возвращать имитацию хранилища
// (это не нужно, если тестируемый класс внедрряет хранилище, которое он
// использует, вместо всего менеджера объектов)
$entityManager = $this->createMock(EntityManager::class);
$entityManager->expects($this->any())
->method('getRepository')
->willReturn($employeeRepository);
$salaryCalculator = new SalaryCalculator($entityManager);
$this->assertEquals(2100, $salaryCalculator->calculateTotalSalary(1));
}
}
В этом примере, вы строите макеты наизнанку, вначале создавая служащего, который
возвращается Repository
, который, в свою очередь, возвращается EntityManager
.
Таким образом, в тестировании не участвует ни один настоящий класс.
Функциональное тестирование хранилища Doctrine
В функциональных тестах вы будете делать запросы к базе данных, используя реальные хранилища Doctrine, вместо того, чтобы имитировать их. Для этого получите менеджер сущностей через сервис-контейнер следующим образом:
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();
// это рекомендуется делать, чтобы избежать утечек памяти
$this->entityManager->close();
$this->entityManager = null;
}
}