Unit testing with session

expressive
session
phpunit

#1

Hello everyone,

I’m rather new to unit testing (better late than never ^^) and I started using PHPUnit based on Zend Expressive skeleton.

I analyzed the 3 available tests and understood how it works.

But my application uses Zend\Expressive\Session\SessionMiddleware so, obviously, the test brakes.

Here is my handler :

public function handle(ServerRequestInterface $request) : ResponseInterface
{
    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);

    if (!$session->has('tempDirectory')) {
        $session->set('tempDirectory', 'data/temp/'.uniqid());
    }

    $data = [];

    return new HtmlResponse($this->template->render('app::home-page', $data));
}

Here is the “error” returned by PHPUnit :

1) AppTest\Handler\HomePageHandlerTest::testReturnsHtmlResponseWhenTemplateRendererProvided
Error: Call to a member function has() on null

I get that during the test the session is not initialized and so PHPUnit can’t use getAttribute(SessionMiddleware::SESSION_ATTRIBUTE) but how can/should I fix this ?

Thanks a lot !


#2

How does your test look like? Usually you’d mock ServerRequestInterface with tools like prophecy to provide a specific state https://phpunit.de/manual/6.5/en/test-doubles.html#test-doubles.prophecy


#3

Thanks @tux-rampage ;
As I mentioned, so for I play with Zend Expressive Skeleton tests : https://github.com/zendframework/zend-expressive-skeleton/blob/master/test/AppTest/Handler/HomePageHandlerTest.php

I already had a look at prophecy documentation but I don’t get how I can “setup” the session in the test.


#4

Take a look at the zend-expression-session tests. It should get you in the right direction: https://github.com/zendframework/zend-expressive-session/blob/master/test/SessionMiddlewareTest.php


#5

Should have thought about that …

Thanks a lot, I’ll have a look !


#6

Considering my handler :

public function handle(ServerRequestInterface $request) : ResponseInterface
{
    $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);

    if (!$session->has('tempDirectory')) {
        $session->set('tempDirectory', 'data/temp/'.uniqid());
    }

    $data = [];

    return new HtmlResponse($this->template->render('app::home-page', $data));
}

I made this test :

class HomePageHandlerTest extends TestCase
{
    /** @var ContainerInterface|ObjectProphecy */
    protected $container;

    /** @var TemplateRendererInterface|ObjectProphecy */
    protected $renderer;

    /** @var RouterInterface|ObjectProphecy */
    protected $router;

    /** @var SessionInterface|ObjectProphecy */
    protected $session;

    protected function setUp()
    {
        $this->container = $this->prophesize(ContainerInterface::class);
        $this->renderer  = $this->prophesize(TemplateRendererInterface::class);
        $this->router    = $this->prophesize(RouterInterface::class);
        $this->session   = $this->prophesize(SessionInterface::class);
    }

    public function testReturnsHtmlResponse()
    {
        $this->session
            ->has('tempDirectory')
            ->willReturn(true);

        $this->renderer
            ->render('app::home-page', Argument::type('array'))
            ->willReturn('');

        $homePage = new UploadHandler(
            $this->router->reveal(),
            $this->renderer->reveal(),
            get_class($this->container->reveal())
        );

        $request = $this->prophesize(ServerRequestInterface::class);
        $request
            ->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE)
            ->willReturn($this->session);

        $response = $homePage->handle(
            $request->reveal()
        );

        $this->assertInstanceOf(HtmlResponse::class, $response);
    }
}

Does it make sense ?
Did I cover “everything” ?
Can it be improved ?

Thanks again for all your help :slight_smile: