Search code examples
symfonyphpunitswiftmailerclassnotfound

symfony 2.1 phpunit Swift_Message class not found


I've an issue with symfony and phpunit. Our peoject is growing bigger and bigger. So we decided to activate process isolation for phpunit because the server couldn't stand the amount of tests anymore (Not enough RAM). Since then all test which send mails aren't working anymore. Could someone please help us? The test below works perfectly fine if processIsolation="false" but it fails if processIsolation="true"

Versions:

  • symfony 2.1.8-dev

  • phpunit 3.7.9

ERROR Message

Project\AppBundle\Tests\MailTest::testSendMail PHPUnit_Framework_Exception: PHP Fatal error: Class 'Swift_Message' not found in /var/www/project/src/Project/AppBundle/Tests/MailTest.php

Test

public function testSendMail()
{
    $client = static::createClient();

    $message = \Swift_Message::newInstance();
    $message->setFrom('[email protected]')
        ->setTo('[email protected]')
        ->setSubject('Subject')
        ->setBody('Hello World')
        ->setContentType('text/html');

    $client->getContainer()->get('mailer')->send($message);
    $this->assertTrue(true);
}

phpunit.xml

<phpunit
    backupGlobals="false"
    backupStaticAttributes="false"
    colors="true"
    convertErrorsToExceptions="true"
    convertNoticesToExceptions="true"
    convertWarningsToExceptions="true"
    bootstrap="./autoload.php"
    processIsolation="true"
    stopOnFailure="false"
    syntaxCheck="false" >

    <testsuites>
        <testsuite name="Project Test Suite">
            <directory>../src/Project/AppBundle/Tests/MailTest.php</directory>
        </testsuite>
</testsuites>
</phpunit>

Solution

  • This error is caused because Switfmailer defines a constant SWIFT_REQUIRED_LOADED after it installs it's autoloader. The autoloader checks this constant, and if it's already defined, refuses to install the autoloader. In process isolation, PHPUnit ensures that all defined constants are re-defined in the processs that gets spawned to run the test. Unfortunately, this means that SWIFT_REQUIRED_LOADED is defined in the test process, so the autoloader doesn't load (see "swift_required.php" in the swiftmailer source directory). Note that if you turn off include global state for the test via annotations your tests still won't work, because the bootstrap file is passed to the test process via the __PHPUNIT_BOOTSTRAP global variable (see TestCaseMethod.tpl in the PHPUnit directory). Without the globals, this global is undefined in the test process and the bootstrap file is not included breaking the tests.

    The only work around that I found that works was to replace the line $constants = PHPUnit_Util_GlobalState::getConstantsAsString(); with $constants = ''; in the run method of TestCase.php in the PHPUnit source distribution. If your code relies on global constants to be defined before your test cases run this fix obviously won't work for you (class constants are a different story); unless said constants will be redefined safely in the course of running your test cases.