Setting up/using a session in a phpunit test

74 Views Asked by At

I have a simple class that wraps around serializing/deserializing an array of objects and adding them to the session and I want to test it.

The errors I've gotten are

  1. the there is no session available.
  2. When trying to construct a session, that the session is already started.

I've dumped the environment while running my test, and it says it's running as test

I can confirm that the accepted answer here is already in my framework.yaml (Symfony PHPUnit : Failed to start session because header have already been sent)

Am I missing some concept? How can I create the session? Or is there some other approach I should be using for this test?

Some code snippets below:

class SessionManager
{
    public function __construct(private RequestStack $requestStack, private SerializerInterface $serializer)
    {
    }

    public function addAttendee(Attendee $attendee): void
    {
        $session = $this->requestStack->getSession();
        $attendees = $this->getAttendees();
        $session->set('attendees', $this->serializer->serialize([...$attendees, $attendee], 'json'));
    }

    /**
     * @return Attendee[]
     */
    public function getAttendees(): array
    {
        $attendees = $this->requestStack->getSession()->get('attendees');
        return $this->serializer->deserialize($attendees, Attendee::class . '[]', 'json');
    }
}

First test approach (and error)

    /** @test */
    public function it_can_set_an_array_of_attendees_into_the_session()
    {
        $sessionManager = static::getContainer()->get(SessionManager::class);
        $attendee = new Attendee('firstname', 'lastname', 'female');
        $sessionManager->addAttendee($attendee);

        $attendees = $sessionManager->getAttendees();
        $this->assertEquals('firstname', $attendees[0]->firstname);
    }
1) App\Tests\Controller\SessionManagerTest::it_can_set_an_array_of_attendees_into_the_session
Symfony\Component\HttpFoundation\Exception\SessionNotFoundException: There is currently no session available.

.../vendor/symfony/http-foundation/RequestStack.php:105
.../src/Controller/SessionManager.php:17
.../tests/Controller/SessionManagerTest.php:48
.../vendor/phpunit/phpunit/phpunit:107

Trying to create and inject a session (and error)

    /** @test */
    public function it_can_set_an_array_of_attendees_into_the_session()
    {
        // Create and start session, add to a Request, add Request to RequestStack, set RequestStack into container
        $session = new Session();
        $session->start();
        $request = new Request();
        $request->setSession($session);
        $requestStack = new RequestStack();
        $requestStack->push($request);
        static::getContainer()->set(RequestStack::class, $requestStack);

        $sessionManager = static::getContainer()->get(SessionManager::class);
        $attendee = new Attendee('firstname', 'lastname', 'female');
        $sessionManager->addAttendee($attendee);

        $attendees = $sessionManager->getAttendees();
        $this->assertEquals('firstname', $attendees[0]->firstname);
    }
1) App\Tests\Controller\SessionManagerTest::it_can_set_an_array_of_attendees_into_the_session
RuntimeException: Failed to start the session because headers have already been sent by ".../vendor/phpunit/phpunit/src/Util/Printer.php" at line 104.

.../vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php:116
.../vendor/symfony/http-foundation/Session/Session.php:59
.../tests/Controller/SessionManagerTest.php:46
.../vendor/phpunit/phpunit/phpunit:107
1

There are 1 best solutions below

1
Bademeister On

I'm not sure why the stream is output in Printer.php on line 104.

Try using the MockFileSessionStorage from Symfony for the UnitTests.

use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage;

class UnitTest extends KernelTestCase
{
    public function it_can_set_an_array_of_attendees_into_the_session()
    {
        $session = new Session(new MockFileSessionStorage());
        // ...  
    }
}