全局状态
使用单件(singleton)的代码很难测试。使用全局变量的代码也一样。通常情况下,欲测代码和全局变量之间会强烈耦合,并且其创建无法控制。另外一个问题是,一个测试对全局变量的改变可能会破坏另外一个测试。
在 PHP 中,全局变量是这样运作的:
-
全局变量
$foo = 'bar';
实际上是存储为$GLOBALS['foo'] = 'bar';
的。 -
$GLOBALS
这个变量是一种被称为超全局变量的变量。 -
超全局变量是一种在任何变量作用域中都总是可用的内建变量。
- 在函数或者方法的变量作用域中,要访问全局变量
$foo
,可以直接访问$GLOBALS['foo']
,或者用global $foo;
来创建一个引用全局变量的局部变量。
除了全局变量,类的静态属性也是一种全局状态。
默认情况下,PHPUnit 用一种更改全局变量与超全局变量($GLOBALS
、$_ENV
、$_POST
、$_GET
、$_COOKIE
、$_SERVER
、$_FILES
、$_REQUEST
)不会影响到其他测试的方式来运行所有测试。同时,还可以选择将这种隔离扩展到类的静态属性。
Note
对全局变量和类的静态属性的备份与还原操作使用了
serialize()
与unserialize()
。
某些类的实例对象(比如 PDO
)无法序列化,因此如果把这样一个对象存放在比如说 $GLOBALS
数组内时,备份操作就会出问题。
在the section called “@backupGlobals”中所讨论的 @backupGlobals
标注可以用来控制对全局变量的备份与还原操作。另外,还可以提供一个全局变量的黑名单,黑名单中的全局变量将被排除于备份与还原操作之外,就像这样:
class MyTest extends PHPUnit_Framework_TestCase
{
protected $backupGlobalsBlacklist = array('globalVariable');
// ...
}
Note
在方法(例如
setUp()
方法)内对$backupGlobalsBlacklist
属性进行设置是无效的。
在 the section called “@backupStaticAttributes” 中提到的 @backupStaticAttributes
标注可以用于在每个测试之前备份所有已声明类的静态属性值并在其后恢复。
它所处理的并不只是测试类自身,而是在测试开始时已声明的所有类。它只作用于静态类属性,不作用于函数内声明的静态变量。
Note
只有启用了
@backupStaticAttributes
的测试方法才会在方法之前执行此操作。如果在此之前运行的某个没有启用@backupStaticAttributes
的测试方法改变了静态属性的值,那么被备份及还原的将会是这个改变后的值——而非初始声明时提供的默认值。PHP 并不额外记录任何静态变量的声明时提供的初始默认值。
同样的情况也发生于测试内部新加载/声明的类的静态属性上。它们也无法在测试结束之后复原为声明时提供的原始默认值,因为无从得知这些默认值。这些被修改过的值会泄漏到后继测试中。
对单元测试而言,推荐在 setUp()
中显式的重置测试中使用到的静态属性(最好同时在 tearDown()
中执行重置,这样就保证不会影响到后继的测试)。
可以提供黑名单来将静态属性从备份与还原操作中排除出去:
class MyTest extends PHPUnit_Framework_TestCase
{
protected $backupStaticAttributesBlacklist = array(
'className' => array('attributeName')
);
// ...
}
Note
在方法(例如
setUp()
)内对$backupStaticAttributesBlacklist
属性进行设置是无效的。