Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

Instead of injecting hacks into production code or to test code, you can set up additional variables directly in phpunit.xml (which you are going to use at some point anyway) in php section:

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

    <php>
        <server name="DOCUMENT_ROOT" value="wwwroot" />
        <server name="SERVER_NAME" value="localhost" />

        <const name="PHPUNIT_TESTSUITE" value="true"/>
    </php>
</phpunit>

Refer to official documentation for other possible options

$_SERVER['DOCUMENT_ROOT'] can also be set in the Bootstrap file and the same Bootstrap_test.php is attached to the phpunit configuration file phpunit.xml with the attribute name bootstrap=Bootstrap_test.php

I was able to achieve the requirement to set $_SERVER['DOCUMENT_ROOT'] for Jenkins job configuration. The "Bootstrap_test.php" looks like

<phpunit

   backupGlobals="false"

   backupStaticAttributes="false"

   strict="true"

   verbose="true"

   bootstrap="Bootstrap_test.php">

   <testsuites>

     <testsuite name="PHPUnit Test Suite">

     <file>PHPUnitTest.php</file>

     </testsuite>

   </testsuites>

   <logging>

     <log type="coverage-clover" target="logs/clover.xml"/>

   </logging>

</phpunit>

and the contents in Bootstrap.php is declared using define() function:

define('BASE_PATH', realpath(dirname(__FILE__)));    
$_SERVER['DOCUMENT_ROOT'] = BASE_PATH;

The BASE_PATH variable will typically hold the full path to the Jenkins job directory. Say, Jenkins job name is Test_Job. The directory where Jenkins will place project source code is /var/lib/jenkins/jobs/Test_Job/workspace (assuming jenkins work directory as /var/lib/jenkins).

If Bootstrap_test.php is placed at the base directory, BASE_PATH will hold /var/lib/jenkins/jobs/Test_Job/workspace and finally set to $_SERVER['DOCUMENT_ROOT'].

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.

Just want to document calling another php files (like config.php) from inside PHPUnit tests.
I have a test class:

class xyzTest extends TestCase {

    public static function setUpBeforeClass() {
        require_once __DIR__ . '/../../app/config/Config.php';
    }

...

In config.php I set up some constants, like file paths. These paths are relative to $_SERVER['DOCUMENT_ROOT'].
I want to test my xyz class using these path constants.
However, the $_SERVER superglobal is empty, when calling PHPUnit from command line. I tried following the good advice from an answer above and set the $_SERVER['DOCUMENT_ROOT'] in PHPUnits setUp methods. This did not fix my issue.

I fixed it by adding an if statement into my Config.php, like so:

if ($_SERVER['DOCUMENT_ROOT']) {
    $DocumentRoot = realpath($_SERVER['DOCUMENT_ROOT']);
} else {
    $DocumentRoot = realpath(dirname(__FILE__) . '/../..'); //for PHPUnit
}

Hope this saves someone headache.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top