DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 963,274 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Cover image for How test your listener events on Symfony with phpunit
Roberto Manchado
Roberto Manchado

Posted on

How test your listener events on Symfony with phpunit

Test a listener using the Symfony's events, is easy.

The listener is listening an event for example, when an exception has happened.
When the onKernelException event has happened, you can intercept the request and catch the data of request
thanks to the ExceptionEvent Object.

In fact, you can transform the response as follows:

class JsonExceptionResponseTransformerListener
{
    public function onKernelException(ExceptionEvent $event): void
    {
        $exception = $event->getThrowable();

        if ($exception instanceof HttpExceptionInterface) {
            $data = [
                'class' => \get_class($exception),
                'code' => $exception->getStatusCode(),
                'message' => $exception->getMessage(),
            ];

            $response = $this->prepareResponse($data, $data['code']);

            $event->setResponse($response);
        }
    }

    private function prepareResponse(array $data, int $statusCode): JsonResponse
    {
        $response = new JsonResponse($data, $statusCode);
        $response->headers->set('Server-Time', \time());
        $response->headers->set('X-Error-Code', $statusCode);

        return $response;
    }
}
Enter fullscreen mode Exit fullscreen mode

On onKernelException you can catch the Exception and prepare a response. You can modify the status of the response and the type of the response for example.
This is useful when you want response with a json response like in an api-app.

But.. how test this with php-unit ??

In a first instance, only need the EventDispatcher. The idea is use an instance of EventDispatcher, and trigger the event with the
ListenerObject that you has created. ( see up )
You don't need Mocks for the ExceptionEvent o dependencies of other classes.

Only, need trigger the event inside phpunit, and catch the event. Then you can use the asserts of php-unit for get the response and the type of the response expected.

Like this:

class JsonExceptionResponseTransformerListener extends TestCase
{

    /** @var EventDispatcher **/
    private $dispatcher;

    public function setUp(){
        $this->dispatcher = new EventDispatcher();
    }

    public function test_should_get_a_json_response() : void
    {
        // instance our own listener
        $listener = new JsonExceptionResponseTransformerListener();
        $this->dispatcher->addListener('onKernelException', [$listener, 'onKernelException']);

        // dispatch your event here
        $event = new ExceptionEvent();
        $dispatcher->dispatch($event, 'onKernelException');
        $this->assertInstanceOf(JsonResponse::class,$event->getResponse());
    }

}
Enter fullscreen mode Exit fullscreen mode

You can , of course, add more assert to the response, like the status code, the params of the header response, etc etc....

fdo:roberto manchado

Top comments (1)

Collapse
 
iulidercaci profile image
Iuli Dercaci

Thank you for a short and very helpful example.
Just one thing to mention - it seems like at least in Symfony ver 4.4, method dispatch accepts parameters in a different order - event name is the first, and the optional Event object is the second:

$dispatcher->dispatch('onKernelException', $event);
Enter fullscreen mode Exit fullscreen mode

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.