PHPUnit and Globals

2020-07-06 09:12发布

I am learning and exploring applications of PHPUnit with PHP 5.2.9 and have run into the globals issue. I have set $backupGlobals to FALSE, included the doc '@backupGlobals disabled' and this doesn't seem to affect the behaviour of PHPUnit's backing up of the globals. Is there something I'm missing? Do I need to alter PHPUnit's xml file? Create a bootstrap?

config.php:

$testString = 'Hello world!';

basicApp.php:

require ('D:\data\clients\security.ca\web_sites\QRASystems.com\wwwroot\__tests\BasicApp\config.php');

class BasicApp {

public $test;

public function __construct() {
    global $testString;
    $this->test = $testString;
}

public function getTest() {
    return $this->test;
}

public function setTest($test){
    $this->test = $test;
}

BasicAppTest.php:

require ('D:\data\clients\security.ca\web_sites\QRASystems.com\wwwroot\__tests\BasicApp\BasicApp.php');

class BasicAppTest extends PHPUnit_Framework_TestCase{
    protected $testClass;
    protected $backupGlobals = FALSE;
    protected $backupGlobalsBlacklist = array('testString');

    public function SetUp(){
        $this->testClass = new BasicApp;
        $this->testClass->bootstrap();
    }

    public function testGlobal(){
        echo $this->testClass->getTest();
        $this->assertNotNull($this->backupGlobals);
        $this->assertFalse($this->backupGlobals);
        $this->assertNotEmpty($this->testClass->test);
    }

    public function testMethods(){
        $this->testClass->setTest('Goodbye World!');
        echo $this->testClass->getTest();
        $this->assertNotNull($this->backupGlobals);
        $this->assertNotNull($this->testClass->test);
        if (empty($this->testClass->test)) echo 'Method set failed!';
    }
}

testGlobal() fails on $this->assertNotEmpty($this->testClass->test), indicating that $this->backupGlobals is set to FALSE and that globals are still being back up by PHPUnit.

EDIT: I got this working by making the following changes-

BasicAppTest.php:

    protected $backupGlobals = FALSE; <- REMOVED
    protected $backupGlobalsBlacklist = array('testString');  <- REMOVED

config.php:

global $testString; <- ADDED
$testString = 'Hello world!';

I am dumbfounded that this hasn't been covered before somewhere!

2条回答
爷的心禁止访问
2楼-- · 2020-07-06 09:29

In your test case you are defining a new $backupGlobals property that PHPUnit won't see. Since the property is protected, you could set it to false in the constructor, but PHPUnit uses its constructors to pass information on how to run the test method. Instead, create a phpunit.xml configuration file to set the backupGlobals property to false.

<phpunit backupGlobals="false">
    <testsuites>
        <testsuite name="Test">
            <directory>.</directory>
        </testsuite>
    </testsuites>
</phpunit>
查看更多
一夜七次
3楼-- · 2020-07-06 09:45

In your edits and comments you've pointed out one workaround for the problem (explicitly declaring globals within the tested application). In onlab's comment to a PHPUnit issue he explains the behavior: when including a file in a function, PHP puts globals from the included files in the function's scope. PHPUnit loads files in a function, and though it tries to extract globals, it fails in the cases I've tried.

Unfortunately, I haven't been able to reproduce the problems of my legacy system in minimal test cases (and I had trouble understanding yours), and so I can't really confirm the explanation. But his suggested workaround helped me: supply a bootstrap file using the --bootstrap option; in it, declare every global used by the tested parts of your application. This avoids the need to modify the application in order to test it. Here's onlab's example from GitHub:

phpunit --bootstrap bootstrap.php test-path

with bootstrap.php:

global $my, $system, $globals, $here;
require_once("/path/to/my/system/bootstrap.php");
查看更多
登录 后发表回答