Martyn
Martyn

Reputation: 6383

PHPUnit - autoload classes within tests

I have the following structure within my project:

/
/app
/app/models/ --UserTable.php

/lib
/lib/framework
/lib/framework/Models
/lib/framework/Db

/tests -- phpunit.xml, bootstrap.php
/tests/app
/tests/app/models --UserTableTest.php

With the app and lib directories I have various classes that work together to run my app. To setup my tests I have create a /tests/phpunit.xml file and a /tests/bootstrap.php

phpunit.xml

<phpunit bootstrap="bootstrap.php">
</phpunit>

bootstrap.php

<?php

function class_auto_loader($className)
{
  $parts = explode('\\', $className);
  $path = '/var/www/phpdev/' . implode('/', $parts) . '.php';

  require_once $path;
}

spl_autoload_register('class_auto_loader');

So I have the following test:

<?php

class UserTableTest extends PHPUnit_Framework_TestCase
{
  protected $_userTable;

  public function setup()
  {
    $this->_userTable = new app\models\UserTable;
  }

  public function testFindRowByPrimaryKey()
  {
    $user = $this->_userTable->find(1);

    $this->assertEquals($user->id, 1);
  }
}

But it can't find the class when I run the test - PHP Fatal error: Class 'app\models\UserTable' not found in /var/www/phpdev/tests/app/models/UserTableTest.php on line 13

What am I doing wrong? I'm trying to understand PHPUnit configuration better so I opted to write the configuration and bootstrap file myself.

Upvotes: 24

Views: 34732

Answers (4)

ImLeo
ImLeo

Reputation: 1003

You probably should use composer to organize your code, for example, the composer.json in your project root directory should contains something like:

  ...
  "autoload": {
    "psr-0": {
      "PRJ_NAME\\APP\\": "app/",
      "PRJ_NAME\\LIB\\": "lib/"
    }
  },
  ...

Then after run composer update, the two namespaces defined above are put into the vendor/composer/autoload_namespaces.php. Next is simple, just run phpunit with the autoload option like this:

phpunit --bootstrap vendor/autoload.php tests/app/models/UserTableTest

Make sure change the usage of your namespace in both your source code and test code.

Upvotes: 5

Raaghu
Raaghu

Reputation: 2014

If you are using composer autoload

change

<phpunit colors="true" strict="true" bootstrap="vendor/autoload.php">

to

<phpunit colors="true" strict="true" bootstrap="tests/autoload.php">

and in tests directory create new autoload.php with following content

include_once __DIR__.'/../vendor/autoload.php';

$classLoader = new \Composer\Autoload\ClassLoader();
$classLoader->addPsr4("Your\\Test\\Namespace\\Here\\", __DIR__, true);
$classLoader->register();

Upvotes: 35

Alex
Alex

Reputation: 3454

In my loader (very close to yours) I check if the first exploded part of the class name is my vendor, if it isn't the loader just return doing nothing (else had issues with phpunit's loader, since I'm a newbie of phpunit and don't know if this is the expected behavior nor if phpunit suggest or provide a loader ready to use).

I keep phpunit.xml in the same directory of tests/ (not within) and once configured <directory>tests</directory> I just run phpunit on command line without configuration or directory options.

Upvotes: 1

Amorphous
Amorphous

Reputation: 772

If you load you classess with the same bootstrap in app you should be able to load them in tests. If you are running test by cd into your test directory just add to your phpunit.xml:

<testsuite name="My Application Tests">
    <directory>./</directory>
</testsuite>

Inside <phpunit></phpunit>

Upvotes: 1

Related Questions