Skip to content

Testing Controller

As described in the previous sections, to test Controller/API, create a test class to extend WebTestCase, which provides a plenty of facilities to handle request and assert response.

Creating PostControllerTest

Run the following command to create a test skeleton.

# php bin/console make:test

Follow the interactive steps to create a test base on WebTestCase.

class PostControllerTest extends WebTestCase
{
    public function testGetAllPosts(): void
    {
        $client = static::createClient();
        $crawler = $client->request('GET', '/posts');

        $this->assertResponseIsSuccessful();

        //
        $response = $client->getResponse();
        $data = $response->getContent();
        //dump($data);
        $this->assertStringContainsString("Symfony and PHP", $data);
    }

}

If you try to run the test, it will fail. At the moment, there is no any data for testing.

Preparing Data for Testing Purpose

The doctrine/doctrine-fixtures-bundle is use for populate sample data for testing purpose, and dama/doctrine-test-bundle ensures the data is restored before evey test is running.

Install doctrine/doctrine-fixtures-bundle and dama/doctrine-test-bundle.

composer require --dev doctrine/doctrine-fixtures-bundle dama/doctrine-test-bundle

Create a new Fixture.

# php bin/console make:fixtures

In the load fucntion, persist some data for tests.

class AppFixtures extends Fixture
{
    public function load(ObjectManager $manager): void
    {
        $data = PostFactory::create("Building Restful APIs with Symfony and PHP 8", "test content");
        $data->addTag(Tag::of( "Symfony"))
            ->addTag( Tag::of("PHP 8"))
            ->addComment(Comment::of("test comment 1"))
            ->addComment(Comment::of("test comment 2"));

        $manager->persist($data);
        $manager->flush();
    }
}

Run the command to load the sample data into database manually.

# php bin/console doctrine:fixtures:load 

Add the following extension configuration into the phpunit.xml.dist, thus the data will be purged and recreated for every test running.

<extensions>
    <extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension"/>
</extensions>

Run the following command to execute PostControllerTest.php .

# php .\vendor\bin\phpunit .\tests\Controller\PostControllerTest.php

Create a test function to verify in the PostControllerTest file.

public function testCreatePost(): void
{
    $client = static::createClient();
    $data = CreatePostDto::of("test title", "test content");
    $crawler = $client->request(
        'POST',
        '/posts',
        [],
        [],
        [],
        $this->getContainer()->get('serializer')->serialize($data, 'json')
    );

    $this->assertResponseIsSuccessful();

    $response = $client->getResponse();
    $url = $response->headers->get('Location');
    //dump($data);
    $this->assertNotNull($url);
    $this->assertStringStartsWith("/posts/", $url);
}

Testing Exception

We have created a PostNotFoundException which is thrown when a Post is not found in the PostController.

Add a test to verify if the post is not found and get a 404 status code.

public function testGetANoneExistingPost(): void
{
    $client = static::createClient();
    $id = Uuid::v4();
    $crawler = $client->request('GET', '/posts/' . $id);

    //
    $response = $client->getResponse();
    $this->assertResponseStatusCodeSame(404);
    $data = $response->getContent();
    $this->assertStringContainsString("Post #" . $id . " was not found", $data);
}

Here we use Uuid:v4 to generate a random UUID, of course it should not exist in the backend database. When get a non-existing post, it should return 404 status code and write error message into the response.