imatic/testing

Library to make testing of Symfony bundles easier

6.0.0-alpha.5 2020-05-05 13:41 UTC

README

Build Status
License: MIT

Testing

This library makes it easy to setup tests including testing project for reusable bundles. It will create all required files so that you can start writing your tests and visualise components of your bundle without necessity of including it into some application (as this library creates such application in testing namespace of your bundle).

Content

Initialize testing project

  • Add phpunit.xml.dist to your repository to configure phpunit
  • Set KERNEL_DIR server variable so that phpunit finds symfony kernel (example value nees to be modified based on bundle name)
<!-- phpunit.xml.dist -->
<phpunit>
    <php>
        <server name="KERNEL_DIR" value="Imatic\Bundle\TestsTemplateBundle\Tests\Fixtures\TestProject\TestKernel"/>
    </php>
</phpunit>
  • Add imatic-testing into your dev dependencies
$ composer require --dev 'imatic/testing'
$ ./vendor/bin/testingbundle-init
  • Command above should create directory structure similar to
Tests
    Fixtures
        TestProject
            config
                config.yml
                routing.yml
            XYZBundle (same name as tested bundle)
                AppXYZBundle.php
            web
                app.php
            console
            TestKernel.php
            WebTestCase.php
    Functional
    Integration
    Unit
    bootstrap.php
  • Directory structure above is created based on template in TestsTemplate directory

PHPUnit

Additional constraints

All additinal constraints usable in symfony functional tests are included in our WebTestCase automatically. If you have your own WebTestCase implementation, you can use our trait WebTestCaseExtension to include our additional constraints in your WebTestCase.

ResponseHasCode

This constraint can be used to assert status codes in symfony functional tests. Usage:

<?php

use Imatic\Testing\Test\WebTestCase;

class ExampleTestCase extends WebTestCase
{
    public function testHomepageReturnsOk()
    {
        $client = static::createClient();
        $client->request('GET', '/');

        $this->assertResponseHasCode(200, $client->getResponse());
    }
}
  • advantage in comparison with asserting 200 with $client->getResponse()->getStatusCode() is that the special assert gives you information about what went wrong instead of giving you just wrong code of the response (e.g. 500)

Usage

Now if you have all configured, you can start writing tests or check your testing project in browser. In order to check your testing project in browser.

Checking your testing project in browser

  • go to the testing project root and run web server

Using PHP's bult-in web server

$ cd Tests/Fixtures/TestProject/
$ ./console server:run --docroot=web
  • now open your browser at url reported by the last command (probably "http://127.0.0.1:8000/app.php")
  • you will see exception now probably because you didn't configure any routes for your project yet
  • you can find more details on the command in symfony documentation

Using other web servers

Using symfony console

  • as you may or may not notice when we talked about testing project directory structure, you have also available symfony console - so that you can run all commands that your bundle or bundles your testing project uses provide
  • see symfony documentation on how to work with console command (note that in our case, the executable running console is called console and is placed in root of the testing project

Writing tests working with database

  • if you use our WebTestCase as parent of your tests, then each test will run in transaction so all your modifications to db are lost (so you have db in state before the test run)
  • see commented test below on how it works
<?php

namespace Imatic\Bundle\DataBundle\Tests\Integration\Data\Command;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Imatic\Bundle\DataBundle\Data\Command\Command;
use Imatic\Bundle\DataBundle\Data\Command\CommandExecutor;
use Imatic\Bundle\DataBundle\Tests\Fixtures\TestProject\ImaticDataBundle\Entity\User;
use Imatic\Bundle\DataBundle\Tests\Fixtures\TestProject\WebTestCase;

// this is our test class wich extends ``WebTestCase`` which ensures
// that each test runs in the same environment (has predictable db state)
class CommandExecutorTest extends WebTestCase
{
    public function testGivenCommandShouldBeSuccessfullyExecuted()
    {
        /* @var $user User */
        $user = $this->getUserRepository()->findOneByName('Adam');

        // here we make sure that the user is not activated
        // so that we can test activating functionality
        $this->assertTrue($user->isActivated());

        $command = new Command('user.deactivate', ['id' => $user->getId()]);
        // here we execute command which activates the user
        // and stores the information into database
        $result = $this->getCommandExecutor()->execute($command);
        $this->assertTrue($result->isSuccessful());

        // here we check that user was activated
        $this->assertFalse($user->isActivated());

        // after this test finishes, user is deactivated because the transaction
        // is rollbacked
    }

    /**
     * @return EntityRepository
     */
    public function getUserRepository()
    {
        return $this->getEntityManager()->getRepository('AppImaticDataBundle:User');
    }

    /**
     * @return EntityManager
     */
    public function getEntityManager()
    {
        return $this->container->get('doctrine.orm.entity_manager');
    }

    /**
     * @return CommandExecutor
     */
    private function getCommandExecutor()
    {
        return $this->container->get('imatic_data.command_executor');
    }
}
  • note that because of doctrine connection wrapper we use - you can write symfony funcional tests and after each test, transaction will still be rollbacked (which is not possible without using the wrapper
doctrine:
    dbal:
        connections:
            default:
                wrapper_class: "Imatic\\Testing\\Doctrine\\DBAL\\PersistedConnection"
  • if you want to load any fixtures, you need to require DoctrineFixturesBundle and specify any fixture. Our WebTestCase load fixtures automatically when DoctrineFixturesBundle is enabled.
  • before running tests database and fixtures is reloaded, if you want to disable this behavior, change env variable TESTING_DATA_INIT in your test configuration
<!-- phpunit.xml.dist -->
<phpunit>
    <php>
        <env name="TESTING_DATA_INIT" value="0" />
    </php>
</phpunit>

Testing project configuration

  • if you need to make changes to the configuration, just edit generated config file which you can find in config/config.yml (relative to the testing project roor)