views:

370

answers:

2

I've just started to use PHPUnit, but I've run into a bit of a snag.

My code uses $_SERVER['DOCUMENT_ROOT'] to compute paths for includes, which works when my apache server is the one running PHP, but DOCUMENT_ROOT is not set when I run phpunit from the command line with "phpunit Tests", so these includes don't work.

Am I missing something in the configuration of PHPUnit? Should it somehow be integrated with apache?

A: 

The best way would be to decouple your code from the use of the $_SERVER or any other global array. For example do

class MyClass
{
    protected $_docroot;

    public function __construct($docroot)
    {
        $this->_docroot = $docroot;
    }

    public function getDocRoot() 
    {
        return $this->_docroot;
    }
}

instead of

class MyClass
{
    public function getDocRoot() 
    {
        return $_SERVER['DOCUMENT_ROOT'];
    }
}

This allows you to do

// in your actual code
$instance = new MyClass($_SERVER['DOCUMENT_ROOT']);
$docroot = $instance->getDocRoot();

// in your test
$instance = new MyClass($variable_holding_the_correct_path);
$docroot = $instance->getDocRoot();

Please be aware that this is just a simple example of decoupling. It might be much more complicated in your case - but generally it's worth the effort, especially if you'r running unit tests.

Stefan Gehrig
The problem then becomes, how do I include the file that contains this class?
Smug Duckling
Ah OK - I see the problem... I slightly misunderstood the real background of your question. You should not rely on including files using any environment variable (including `$_SERVER['DOCUMENT_ROOT']`). Would it be possible that you include your files using relative paths, e.g. `require_once dirname(__FILE__) . '/MyClass.php'`? On the other hand you could set up some sort of autoloading...
Stefan Gehrig
+3  A: 

Late answer, sorry.

No, you're not missing anything. PHP CLI (PHP for the Command Line) is a different beast than PHP as an Apache / CGI module.

What you could do, though is change the setUp() of your files to set $_SERVER['DOCUMENT_ROOT'] to what you need (since $_SERVER is still available as a superglobal even in CLI context), e.g. :

public function setUp() {
  $_SERVER['DOCUMENT_ROOT'] = dirname(__FILE__) . "/../application";
}

Just be careful, you probably want to put this into your tearDown():

public function tearDown() {
  unset($_SERVER['DOCUMENT_ROOT']);
}

PHPUnit backs up your global state if you use global (also superglobal) data at all, which can slow your tests down dramatically, hence why it's better to avoid having any after a test has run through.

pinkgothic