Search code examples
phpnamespacesphpunitautoloadspl-autoload-register

PHPUnit cannot find classes via namespace autoloading


We have following, simplified folder structure:

phpunit.xml
autoloading.php
index.php

/models
    /user
        user.php
        ...

    /settings
        preferences.php
        ...

/tests
    test.php

This is the content of the relevant files:

models/user/user.php

namespace models\user;

class User {

    private $preferences;

    public function __construct()
    {
        $this->preferences = new \models\settings\Preferences();
    }

    public function getPreferenceType()
    {
        return $this->preferences->getType();
    }
}

models/settings/preferences.php

namespace models\settings;

class Preferences {

    private $type;

    public function __construct($type = 'default')
    {
        $this->type = $type;
    }

    public function getType()
    {
        return $this->type;
    }
}

autoloading.php

spl_autoload_extensions('.php');
spl_autoload_register();

index.php

require_once 'autoloading.php';

$user = new \models\user\User();
echo $user->getPreferenceType();

When we run index.php, everything works fine with automatic autoloading via namespace. Since the namespace fits the folder structure, everything is loaded automagically.

We would now like to setup some PHPUnit tests (via phpunit.phar, not composer), that do also use the same autoloading mechanism:

phpunit.xml

<phpunit bootstrap="autoloading.php">
    <testsuites>
        <testsuite name="My Test Suite">
            <file>tests/test.php</file>
        </testsuite>
    </testsuites>
</phpunit>

tests/test.php

class Test extends PHPUnit_Framework_TestCase
{
    public function testAccess()
    {
        $user = new \models\user\User();
        $this->assertEquals('default', $user->getPreferenceType());
    }
}

When we run the test, however, we get following error:

Fatal error: Class 'models\user\User' not found in tests\test.php on line 7

We could of course add following method to our test:

public function setup()
{
    require_once '../models/user/user.php';
}

But then following error would occur, etc.:

Fatal error: Class 'models\settings\Preferences' not found in models\user\user.php on line 11

Any idea what we have to change so that autoloading works within the tests as well? We have tried so many things, but it just won't work.

Thank you!


Solution

  • We have found a workaround to our problem:

    Instead of using our own autoloading.php file (see above) we are now using psr-4 autoloading via composer. Our composer.json file looks like this:

    {
      "autoload": {
        "psr-4": {
          "models\\": "models/"
        }
      }
    }
    

    After having triggered composer install a new folder vendor is being created, containing autoload.php. This file can be required within index.php as well as in phpunit.xml (<phpunit bootstrap="vendor/autoload.php">).

    With this autoloading setup (while still using the same namespaces) everything works seamlessly.