1

I am new to Symfony, I have wrote small app now have to add unit tests, here is my controller:

<?php
namespace myBundle\Controller;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;

class IndexController extends AbstractController
{

    /**
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function indexAction(Request $request)
    {

        if ($this->getRequest()->isMethod('POST')) {
            // Do Something
        }

        // Do Something otherwise
    }
}

My test:

class IndexControllerTest extends \PHPUnit_Framework_TestCase
{
    protected $testController;

    public function setUp()
    {

        $this->testController =
            $this->getMockBuilder('myBundle\Controller\IndexController')
                ->disableOriginalConstructor()
                ->getMock();

    }

    public function testPostSaveActionWithBadRequest()
    {
        $expectation = 'Some text ';

        $response = $this->testController->indexAction(new Request);
        $this->assertInstanceOf(
            'Symfony\Component\HttpFoundation\JsonResponse',
            $response
        );
        $content = json_decode($response->getContent());
        $this->assertEquals($expectation, $content->error);
    }

}

When I run this test I get following:

PHP Fatal error: Call to a member function get()

which is basically on following line

if ($this->getRequest()->isMethod('POST')) {

this tells me the container is null (I verified it by printing dump of the container).

any idea what am I missing here or is there a way to provide container as dependency for that test.

I really appreciate all the help.

thanks FI

3
  • 2
    I would not write unit tests for controller that extend the Controller class from the FrameworkBundle. As you just noticed mocking the container becomes a nightmare. I would either register the controller as a service and inject all dependencies explicitly or create functional tests instead.
    – xabbuh
    Commented Jan 3, 2016 at 19:57
  • If you test your webpage in browser does it work? What kind of class is AbstractController? Have you also considered using Symfony\Bundle\FrameworkBundle\Test\WebTestCase instead of \PHPUnit_Framework_TestCase?
    – honzalilak
    Commented Jan 3, 2016 at 22:39
  • @honzalilak yes I have tried Symfony\Bundle\FrameworkBundle\Test\WebTestCase amd the abstract controller I have is nothing mush I just add information about logging and adding some JS Commented Jan 3, 2016 at 23:24

1 Answer 1

4

You're trying to mock the class you're suppose to test:

$this->testController =
    $this->getMockBuilder('myBundle\Controller\IndexController')
        ->disableOriginalConstructor()
        ->getMock();

You should actually instantiate the class you're testing, and mock or stub its collaborators.

However, in this particular scenario, instead of writing a unit test, write a functional test. There's a chapter on writing functional tests in Symfony docs that'll help you.

Your controller uses lots of framework classes (classes that don't belong to you), and you shouldn't mock them either. That's why functional tests are better in this case. Also, make sure you move as much code as possible out of your controller, so you can properly unit test that part (and write as little functional tests as possible).

In the meantime read some books on unit testing (in the following order):

3
  • even as a service I get container but request is still NULL i.e. $this->getRequest() == NULL Commented Jan 6, 2016 at 12:45
  • It won't magically appear there. This is one of the reasons you should write integration tests, rather than unit tests for code that uses third party classes - you might be wrong in assumptions what third party classes do for you. Symfony sets the request on request stack service with one of your listeners. You are most likely not doing the same in your test and therefore getRequest() returns null. Commented Jan 6, 2016 at 14:26
  • Also, rather than using getRequest() in your controller pass it to the action method. You'll be able to pass it in your unit test. Commented Jan 6, 2016 at 14:27

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.