如何测试使用全局变量的PHP代码


How would you test PHP code which uses global variable?

假设类Account(在Account.php文件中)使用$DB变量在数据库中存储数据。$DB变量在另一个globals.php文件中初始化。


/**** globals.php ****/
$DB = PDO (....);

/**** account.php ****/
public function create($data) {
global $DB;
....
}

现在,假设您想使用PHPUnit测试来测试account类create中的一个函数。您将如何初始化$DB对象?

理想情况下,您不应该使用隐藏依赖关系的全局变量,因为全局变量的更改可能会导致事情发生。

你可以破解并替换你的变量,这样你就可以模拟它。你可以使用setUp方法来存储全局$DB中的内容,然后在teardown()方法中恢复它。这样,您就不会意外地用mock破坏其他测试。

public function setUp() {
    global $DB;
    $this->oldDB = $DB;
}
public function testCreate() {
    $mockDB = $this->getMock('PDO') ... //More steps to complete mock object
    global $DB;
    $DB = $mockDB;
    //Rest of Test here
}
public function teardown() {
    global $DB;
    $DB = $this->oldDB;
}

现在,仅仅因为你可以这样做,并不意味着你应该这样做。最好重构代码,使其不依赖于全局范围。但是,如果目前还不能这样做,那么这里有一个解决方案,它至少会使测试在重构之前可用。

您将如何初始化$DB对象?

只需像往常一样初始化:

class TestCase extends PHPUnit_Framework_TestCase
{
    function testDatabaseConnection()
    {
        require 'path/to/globals.php'; // take "global" variable in local scope
        $GLOBALS['DB'] = $DB; // make it globally available
        $account = new account();
        $this->assertInstanceOf('account', $account);
        $this->assertTrue($account->create("data"));
        ...
    }
}

然后从测试开始,当您对代码进行彻底测试时,可以感受到代码的行为。

然后可以考虑在创建测试类之前初始化数据库连接,这样可以更快地编写测试例程。

  • 第4章。固定装置

稍后,您可能会为自己编写一个助手方法来实例化帐户类。

这时,您可能也会意识到,将数据库连接对象注入构造函数可能不会那么糟糕。