4

When unit testing in Symfony 2, the controller I'm testing does not receive the service container causing the test to fail with the good old Call to a member function get() on a non-object

I can't use $this->forward from the testing controller as it also does not have the service container.

I found this reference but it seems as though I would be using it for the wrong reason, has anyone had any experience with this?

http://symfony.com/doc/current/book/testing.html#accessing-the-container

Edit: Here is my test:

<?php

namespace HvH\ClientsBundle\Tests\Controller;

use HvH\ClientsBundle\Controller\ClientsController;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\HeaderBag;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class ClientsControllerTest extends WebTestCase
{

    public function testGetClientsAction()
    {

        $client = static::createClient();
        $container = $client->getContainer();
        $session = $container->get('session');
        $session->set('key', 'value');
        $session->save();

        $request = new Request;
        $request->create('/clients/123456', 'GET', array(), array(), array(), array(), '');

        $headers['X-Requested-With'] = "XMLHttpRequest";
        $request->headers->add($headers);

        /* This doesn't work */
        /*
        $controller = new Controller;
        $status = $controller->forward( 'HvHClientsBundle:Clients:getClients', array('request' => $request) );        
        */

        $clients_controller = new ClientsController();
        $status = $clients_controller->getClientsAction($request);

        $this->assertEquals(200, $status);
    }

}

Here is the part of the clients controller where it fails

<?php

namespace HvH\ClientsBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use HvH\APIschemaBundle\Controller\Validation;


//FOSRestBundle
use FOS\RestBundle\View\View;

class ClientsController extends Controller
{

    //Query all clients
    public function getClientsAction(Request $request)
    {
        $request_type = $request->headers->get('X-Requested-With');

        if($request_type != 'XMLHttpRequest') {
            return $this->render('HvHDashboardBundle:Dashboard:dashboard.html.twig' );          
        }

        //get any query strings
        $query_strings = $request->query->all();
        $definition = $this->get("service.handler")->definition_handler(__CLASS__, __FUNCTION__);
        //once data has been prepared 
        return $this->get('fos_rest.view_handler')->handle($view);

    }    
}
6
  • Would it be possible to provide a minimal example of your test class, including the declaration and a method which attempts to use the container? Commented Jul 17, 2012 at 16:33
  • Thanks for the response, i've updated with example of the test and the controller that is being tested. it fails at the custom service line $definition = $this->get("service.handler")->definition_handler(__CLASS__, __FUNCTION__); Commented Jul 17, 2012 at 17:54
  • The reason the controller isn't getting a container is because you are attempting to instantiate and interact with it directly rather than using the $client to issue requests. I can give you an example but I'm a little confused as to why getClientsAction takes a Request as a parameter. Is the action operating on this request object or could you instead get the request using "$request = $this->get('request');" as is usually done inside a subclass of Controller? Commented Jul 17, 2012 at 19:19
  • I've taken the Request out of the params and added it in like you said. If you could give me an example that would be great! Commented Jul 17, 2012 at 19:31
  • Would it also be possible to see the route definition for the getClientsAction()? Commented Jul 17, 2012 at 19:32

1 Answer 1

4

I think the reason the controller isn't getting a container is because you are trying to instantiate and interact with it directly rather than simulating requests using the client (See the section on Functional Tests in the Testing section of the Symfony2 book).

You need something more like this (not sure if the route is correct):

public function testGetClientsAction()
{
    $client = static::createClient();

    $client->request(
        'GET', '/clients/123456', 
        array(), /* request params */ 
        array(), /* files */
        array('X-Requested-With' => "XMLHttpRequest"),
    );

    $this->assertEquals(200, $client->getResponse()->getStatusCode());  
}

Note also, the request() method returns a crawler instance which provides helper methods to verify the content of the response if required.

Sign up to request clarification or add additional context in comments.

2 Comments

Great answer! Thanks! Looking promising but now I'm redirecting to the login, I'm sure I can figure this one out myself but if you have a link handy that would be great.
This link did the trick for the auth: symfony.com/doc/current/cookbook/testing/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.