Test your Symfony Controller and your service with PhpUnit

21 May 2015 - Tags: php

In this article I would like share with you a little experience with:

  • Symfony MVC
  • PhpUnit
  • Symfony Dependence Injaction

This is an example of very easy controller.

<?php
namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class SomeStuffController extends FOSRestController
{
/**
* @Rest\Post("/go")
* @return array
*/

public function goAction(Request $request)
{
if($this->container->getParameter("do_stuff")) {
$body = $this->container->get("stuff.service")->splash($request->getContent());
}
return [];
}
}

$this->container->getParameter("do_stuff") is a boolean parameter that enable or disable a feature, How can I test this snippet? I can try to write a functional test but in my opinion is easier write a series of unit tests with PhpUnit to validate my expectations.

Expectations

  • If do_stuff parameter is false function get by my container will be call zero times
  • If do_stuff parameter is true function get by my container will be call one times
<?php

namespace AppBundle\Tests\Controller;

use Liip\FunctionalTestBundle\Test\WebTestCase;
use AppBundle\Controller\SomeStuffController;

class SomeStuffControllerTest extends WebTestCase
{
public function testDoStuffIsTrue()
{
$request = $this->getMock("Symfony\Component\HttpFoundation\Request");
$container = $this->getMock("Symfony\Component\DependencyInjection\ContainerInterface");
$service = $this->getMockBuilder("Some\Stuff")->disableOriginalConstructor()->getMock();
$container->expects($this->once())
->method("getParameter")
->with($this->equalTo('do_stuff'))
->will($this->returnValue(true));

$container->expects($this->once())
->method("get")
->with($this->equalTo('stuff.service'))
->will($this->returnValue($service));

$controller = new SameStuffController();
$controller->setContainer($container);

$controller->goAction($request);

}
}

This is my first expetection “If do_stuff param is true I call stuff.service”. In this controller I use a few objects, Http\Request, Container and stuff.service in this example is a Some\Stuff class. In the first step I have created one mock for each object.

<?php
$request = $this->getMock("Symfony\Component\HttpFoundation\Request");
$container = $this->getMock("Symfony\Component\DependencyInjection\ContainerInterface");
$service = $this->getMockBuilder("Some\Stuff")->disableOriginalConstructor()->getMock();

In the second step I have written my first expetctation, “Call only one time function getParameter from $container with argument do_stuff and it returns true”.

<?php
$container->expects($this->once())
->method("getParameter")
->with($this->equalTo('do_stuff'))
->will($this->returnValue(true));

Thanks at this definitions I know that there will be another effect, my action will call only one time $container->get("stuff.service") and it will be return an Some\Stuff object.

The second test that we can write is “if do_stuff is false $contaner->get("stuff.service") it will not be called.

<?php
public function testDoStuffIsFalse()
{
$request = $this->getMock("Symfony\Component\HttpFoundation\Request");
$container = $this->getMock("Symfony\Component\DependencyInjection\ContainerInterface");
$service = $this->getMockBuilder("Some\Stuff")->disableOriginalConstructor()->getMock();
$container->expects($this->once())
->method("getParameter")
->with($this->equalTo('do_stuff'))
->will($this->returnValue(false));

$container->expects($this->never())
->method("get")
->with($this->equalTo('stuff.service'))
->will($this->returnValue($service));

$controller = new SameStuffController();
$controller->setContainer($container);
$controller->goAction($request);
}