In this example we are going to test a controller 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"
},
...
},
...
}

CustomerController


namespace PhpunitBundle\Controller;

use PhpunitBundle\Service\CustomerService;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* @Route("/customers", service="phpunit.controller.customer")
*/
class CustomerController
{
private $customerService;

public function __construct(
CustomerService $customerService
) {
$this->customerService = $customerService;
}

/**
* @Method({"GET"})
* @Route("")
*
* @return Response
*/
public function getAllAction()
{
$result = $this->customerService->getAll();

return new Response(json_encode($result));
}

/**
* @param int $id
*
* @Method({"GET"})
* @Route("/{id}", requirements={"id"="\d+"})
*
* @return Response
*/
public function getOneAction($id)
{
$result = $this->customerService->getOne($id);

return new Response(json_encode($result));
}

/**
* @param Request $request
*
* @Method({"POST"})
* @Route("")
*
* @return Response
*/
public function createOneAction(Request $request)
{
$payload = json_decode($request->getContent(), true);

$result = $this->customerService->createOne($payload);

return new Response($result, Response::HTTP_CREATED);
}

/**
* @param int $id
* @param Request $request
*
* @Method({"PATCH"})
* @Route("/{id}", requirements={"id"="\d+"})
*
* @return Response
*/
public function updateOneAction(Request $request, $id)
{
$payload = json_decode($request->getContent(), true);

$this->customerService->updateOne($payload, $id);

return new Response();
}

/**
* @param int $id
*
* @Method({"DELETE"})
* @Route("/{id}", requirements={"id"="\d+"})
*
* @return Response
*/
public function deleteOneAction($id)
{
$this->customerService->deleteOne($id);

return new Response();
}
}

services:
phpunit.controller.customer:
class: PhpunitBundle\Controller\CustomerController
arguments:
- "@phpunit.service.customer"

CustomerControllerTest


namespace tests\PhpunitBundle\Controller;

use DateTime;
use PhpunitBundle\Controller\CustomerController;
use PhpunitBundle\Entity\Customer;
use PhpunitBundle\Service\CustomerService;
use PHPUnit\Framework\TestCase;
use PHPUnit_Framework_MockObject_MockObject;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class CustomerControllerTest extends TestCase
{
/** @var CustomerService|PHPUnit_Framework_MockObject_MockObject */
private $customerServiceMock;
/** @var CustomerController|PHPUnit_Framework_MockObject_MockObject */
private $customerControllerMock;

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

$this->customerControllerMock = new CustomerController(
$this->customerServiceMock
);
}

protected function tearDown()
{
$this->customerServiceMock = null;
$this->customerControllerMock = null;
}

/**
* @dataProvider getAllActionDataProvider
*/
public function testGetAllAction($customers)
{
$this->customerServiceMock
->expects($this->once())
->method('getAll')
->willReturn($customers);

$result = $this->customerControllerMock->getAllAction();

$response = new Response(json_encode($customers));

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

public function testGetOneAction()
{
$id = 1;

$customer = new Customer();
$customer->setId($id);
$customer->setName('Name 1');
$customer->setDob(new DateTime());

$this->customerServiceMock
->expects($this->once())
->method('getOne')
->with($id)
->willReturn($customer);

$result = $this->customerControllerMock->getOneAction($id);

$response = new Response(json_encode($customer));

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

public function testCreateOneAction()
{
$id = 1;
$payload = '{"name":"Name 1", "dob":"2017-01-01"}';

$requestMock = $this->getMockBuilder(Request::class)
->disableOriginalConstructor()
->getMock();

$requestMock
->expects($this->once())
->method('getContent')
->willReturn($payload);

$this->customerServiceMock
->expects($this->once())
->method('createOne')
->with(json_decode($payload, true))
->willReturn($id);

$result = $this->customerControllerMock->createOneAction($requestMock);

$response = new Response($id, Response::HTTP_CREATED);

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

public function testUpdateOneAction()
{
$id = 1;
$payload = '{"name":"Name 1", "dob":"2017-01-01"}';

$requestMock = $this->getMockBuilder(Request::class)
->disableOriginalConstructor()
->getMock();

$requestMock
->expects($this->once())
->method('getContent')
->willReturn($payload);

$this->customerServiceMock
->expects($this->once())
->method('updateOne')
->with(json_decode($payload, true), $id);

$result = $this->customerControllerMock->updateOneAction($requestMock, $id);

$response = new Response();

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

public function testDeleteOneAction()
{
$id = 1;

$this->customerServiceMock
->expects($this->once())
->method('deleteOne')
->with($id);

$result = $this->customerControllerMock->deleteOneAction($id);

$response = new Response();

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

public function getAllActionDataProvider()
{
$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],
[$customers1],
[$customers2]
];
}
}