phpphpunit

phpunit runs test twice - gets two answers. Why?


This is my phpunit test file

<?php // DemoTest - test to prove the point

function __autoload($className) {
    //  pick file up from current directory
    $f = $className.'.php'; 
    require_once $f;
}

class DemoTest extends PHPUnit_Framework_TestCase {
    // call same test twice - det different results 
    function test01() {
        $this->controller = new demo();
        ob_start();
        $this->controller->handleit();
        $result = ob_get_clean();  
        $expect = 'Actions is an array';
        $this->assertEquals($expect,$result);
    }

    function test02() {
        $this->test01();
    }
}
?>

This is the file under test

<?php // demo.php
global $actions;
$actions=array('one','two','three');
class demo {
    function handleit() {
        global $actions;
        if (is_null($actions)) {
            print "Actions is null";
        } else {
            print('Actions is an array');
        }
    }
}
?>

The result is that the second test fails because $actions is null.

My question is - why don't I get the same results for the two tests?

Is this a bug in phpunit or it is my understanding of php?


Solution

  • PHPUnit has a feature called "backup globals", if turned on, then at the beginning of the test all variables in global scope are backed up (a snapshot is made of current values) and after each test is completed, the values will be restored again to the original values. You can read more about that here: http://sebastian-bergmann.de/archives/797-Global-Variables-and-PHPUnit.html#content

    Now let's look at your test suite.

    1. test01 is prepared
    2. backup is made of all global variables (at this point $actions in global scope is not set, because the code has not ran yet)
    3. test01 runs
    4. demo.php is included (thanks to autoload) and $actions is set in global scope
    5. your assertion succeeds, because $actions is set in global scope
    6. test01 is torn down. global variables are returned to their original value. $actions in global scope is destroyed at this point, because it was set inside the test, it was not part of the global state before the start of the test
    7. test02 runs .. and fails, because there is no $actions in global scope.

    Direct fix to your problem: include demo.php at the beginning of DemoTest.php, this way $actions ends up in the global scope that is backed up and restored before and after every test.

    Long term fix: try to avoid the use of globals. It's just a bad habit and there are always better solutions than global state using 'global'.