In this example we are going to test a service class which performs create, read, update and delete operations with PHPUnit.


Composer.json


This is what our settings look like.


{
...
"require": {
"php": ">=7.1.1",
...
},
"require-dev": {
"phpunit/phpunit": "^6.4"
},
"config": {
"platform": {
"php": "7.1.11"
},
...
},
...
}

CustomerService


namespace PhpunitBundle\Service;

use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use PhpunitBundle\Entity\Customer;
use PhpunitBundle\Repository\CustomerRepository;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class CustomerService
{
private $customerRepository;
private $entityManager;

public function __construct(
CustomerRepository $customerRepository,
EntityManagerInterface $entityManager
) {
$this->customerRepository = $customerRepository;
$this->entityManager = $entityManager;
}

public function getAll()
{
return $this->customerRepository->findAll();
}

public function getOne($id)
{
return $this->customerRepository->findOneById($id);
}

public function createOne(array $payload)
{
$customer = new Customer();
$customer->setName($payload['name']);
$customer->setDob(new DateTime($payload['dob']));

$this->entityManager->persist($customer);
$this->entityManager->flush();

return $customer->getId();
}

public function updateOne(array $payload, $id)
{
$customer = $this->customerRepository->findOneById($id);
if (!$customer instanceof Customer) {
throw new BadRequestHttpException(sprintf('Customer with id [%s] not found', $id));
}

$customer->setName($payload['name']);
$customer->setDob(new DateTime($payload['dob']));

$this->entityManager->flush();
}

public function deleteOne($id)
{
$customer = $this->customerRepository->findOneById($id);
if (!$customer instanceof Customer) {
throw new BadRequestHttpException(sprintf('Customer with id [%s] not found', $id));
}

$this->entityManager->remove($customer);
$this->entityManager->flush();
}
}

services:
phpunit.service.customer:
class: PhpunitBundle\Service\CustomerService
arguments:
- "@phpunit.repository.customer"
- "@doctrine.orm.entity_manager"

CustomerRepository


namespace PhpunitBundle\Repository;

use Doctrine\ORM\EntityRepository;

class CustomerRepository extends EntityRepository
{
public function findAll()
{
return $this->createQueryBuilder('c')
->getQuery()
->getArrayResult();
}

public function findOneById($id)
{
return $this->createQueryBuilder('c')
->where('c.id = :id')
->setParameter('id', $id)
->getQuery()
->getOneOrNullResult();
}
}

services:
phpunit.repository.customer:
class: PhpunitBundle\Service\CustomerRepository
factory: [ "@doctrine.orm.entity_manager", getRepository ]
arguments:
- PhpunitBundle\Entity\Customer

CustomerServiceTest


namespace tests\PhpunitBundle\Service;

use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use PhpunitBundle\Entity\Customer;
use PhpunitBundle\Repository\CustomerRepository;
use PhpunitBundle\Service\CustomerService;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class CustomerServiceTest extends TestCase
{
/** @var CustomerRepository|PHPUnit_Framework_MockObject_MockObject */
private $customerRepositoryMock;
/** @var EntityManagerInterface|PHPUnit_Framework_MockObject_MockObject */
private $entityManagerInterfaceMock;
/** @var CustomerService */
private $customerService;

protected function setUp()
{
$this->customerRepositoryMock = $this->getMockBuilder(CustomerRepository::class)
->disableOriginalConstructor()
->getMock();

$this->entityManagerInterfaceMock = $this->getMockBuilder(EntityManagerInterface::class)
->disableOriginalConstructor()
->getMock();

$this->customerService = new CustomerService(
$this->customerRepositoryMock,
$this->entityManagerInterfaceMock
);
}

protected function tearDown()
{
$this->customerRepositoryMock = null;
$this->entityManagerInterfaceMock = null;
$this->customerService = null;
}

/**
* @dataProvider getAllCustomerDataProvider
*/
public function testGetAll($customers, $expected)
{
$this->customerRepositoryMock
->expects($this->once())
->method('findAll')
->willReturn($customers);

$result = $this->customerService->getAll();

$this->assertEquals($expected, $result);
}

/**
* @dataProvider getOneCustomerDataProvider
*/
public function testGetOne($id, $customer, $expected)
{
$this->customerRepositoryMock
->expects($this->any())
->method('findOneById')
->with($id)
->willReturn($customer);

$result = $this->customerService->getOne($id);

$this->assertEquals($expected, $result);
}

public function testCreateOne()
{
$customer = new Customer();
$customer->setName('Name 1');
$customer->setDob(new DateTime('2017-01-01'));

$this->entityManagerInterfaceMock
->expects($this->once())
->method('persist')
->with($customer);

$this->entityManagerInterfaceMock
->expects($this->once())
->method('flush');

$result = $this->customerService->createOne(['name' => 'Name 1', 'dob' => '2017-01-01']);

$this->assertEquals($customer->getId(), $result);
$this->assertEquals($customer->getName(), 'Name 1');
$this->assertEquals($customer->getDob(), new DateTime('2017-01-01'));
}

public function testUpdateOneShouldThrowExceptionForInvalidCustomerId()
{
$id = 666;

$this->customerRepositoryMock
->expects($this->once())
->method('findOneById')
->with($id)
->willReturn(null);

$this->expectException(BadRequestHttpException::class);
$this->expectExceptionMessage(sprintf('Customer with id [%s] not found', $id));

$this->customerService->updateOne(['name' => 'New Name 1', 'dob' => '2017-01-11'], $id);
}

/**
* @dataProvider getUpdateOneCustomerDataProvider
*/
public function testUpdateOne($id, $customer)
{
$this->customerRepositoryMock
->expects($this->once())
->method('findOneById')
->with($id)
->willReturn($customer);

$this->entityManagerInterfaceMock
->expects($this->once())
->method('flush');

$this->customerService->updateOne(['name' => 'New Name 1', 'dob' => '2017-01-11'], $id);

$this->assertEquals($customer->getName(), 'New Name 1');
$this->assertEquals($customer->getDob(), new DateTime('2017-01-11'));
}

public function testDeleteOneShouldThrowExceptionForInvalidCustomerId()
{
$id = 666;

$this->customerRepositoryMock
->expects($this->once())
->method('findOneById')
->with($id)
->willReturn(null);

$this->expectException(BadRequestHttpException::class);
$this->expectExceptionMessage(sprintf('Customer with id [%s] not found', $id));

$this->customerService->deleteOne($id);
}

/**
* @dataProvider getRemoveOneCustomerDataProvider
*/
public function testDeleteOne($id, $customer)
{
$this->customerRepositoryMock
->expects($this->once())
->method('findOneById')
->with($id)
->willReturn($customer);

$this->entityManagerInterfaceMock
->expects($this->once())
->method('remove')
->with($customer);

$this->entityManagerInterfaceMock
->expects($this->once())
->method('flush');

$this->customerService->deleteOne($id);
}

public function getAllCustomerDataProvider()
{
$c0 = [];
$customers0 = [$c0];

$c1 = new Customer();
$c1->setId(1);
$c1->setName('Name 1');
$c1->setDob(new DateTime());
$customers1 = [$c1];

$c2 = new Customer();
$c2->setId(2);
$c2->setName('Name 2');
$c2->setDob(new DateTime());
$customers2 = [$c1, $c2];

return [
[$customers0, $customers0],
[$customers1, $customers1],
[$customers2, $customers2]
];
}

public function getOneCustomerDataProvider()
{
$id0 = 0;
$c0 = null;
$customers0 = $c0;

$id1 = 1;
$c1 = new Customer();
$c1->setId($id1);
$c1->setName('Name 1');
$c1->setDob(new DateTime());
$customers1 = $c1;

return [
[$id0, $customers0, $c0],
[$id1, $customers1, $c1],
];
}

public function getUpdateOneCustomerDataProvider()
{
$customer = new Customer();
$customer->setId(1);
$customer->setName('Name 1');
$customer->setDob(new DateTime('2017-01-01'));

return [
[1, $customer],
];
}

public function getRemoveOneCustomerDataProvider()
{
$customer = new Customer();
$customer->setId(1);
$customer->setName('Name 1');
$customer->setDob(new DateTime('2017-01-01'));

return [
[1, $customer],
];
}
}