# 全局状态
[使用单件(singleton)的代码很难测试。](http://googletesting.blogspot.com/2008/05/tott-using-dependancy-injection-to.html)使用全局变量的代码也一样。通常情况下,欲测代码和全局变量之间会强烈耦合,并且其创建无法控制。另外一个问题是,一个测试对全局变量的改变可能会破坏另外一个测试。
在 PHP 中,全局变量是这样运作的:
- 全局变量 `$foo = 'bar';` 实际上是存储为 `$GLOBALS['foo'] = 'bar';` 的。
- `$GLOBALS`这个变量是一种被称为*超全局*变量的变量。
- 超全局变量是一种在任何变量作用域中都总是可用的内建变量。
- 在函数或者方法的变量作用域中,要访问全局变量 `$foo`,可以直接访问 `$GLOBALS['foo']`,或者用 `global $foo;` 来创建一个引用全局变量的局部变量。
除了全局变量,类的静态属性也是一种全局状态。
默认情况下,PHPUnit 用一种更改全局变量与超全局变量(`$GLOBALS`、`$_ENV`、`$_POST`、`$_GET`、`$_COOKIE`、`$_SERVER`、`$_FILES`、`$_REQUEST`)不会影响到其他测试的方式来运行所有测试。同时,还可以选择将这种隔离扩展到类的静态属性。
>[info] ### Note
> 对全局变量和类的静态属性的备份与还原操作使用了 `serialize()` 与 `unserialize()`。
某些类的实例对象(比如 `PDO`)无法序列化,因此如果把这样一个对象存放在比如说 `$GLOBALS` 数组内时,备份操作就会出问题。
在[the section called “@backupGlobals”](# "@backupGlobals")中所讨论的 `@backupGlobals` 标注可以用来控制对全局变量的备份与还原操作。另外,还可以提供一个全局变量的黑名单,黑名单中的全局变量将被排除于备份与还原操作之外,就像这样:
~~~
class MyTest extends PHPUnit_Framework_TestCase
{
protected $backupGlobalsBlacklist = array('globalVariable');
// ...
}
~~~
>[info] ### Note
> 在方法(例如 `setUp()` 方法)内对 `$backupGlobalsBlacklist` 属性进行设置是无效的。
在 [the section called “@backupStaticAttributes”](# "@backupStaticAttributes") 中提到的 `@backupStaticAttributes` 标注可以用于在每个测试之前备份所有已声明类的静态属性值并在其后恢复。
它所处理的并不只是测试类自身,而是在测试开始时已声明的所有类。它只作用于静态类属性,不作用于函数内声明的静态变量。
>[info] ### Note
> 只有启用了 `@backupStaticAttributes` 的测试方法才会在方法之前执行此操作。如果在此之前运行的某个没有启用 `@backupStaticAttributes` 的测试方法改变了静态属性的值,那么被备份及还原的将会是这个改变后的值——而非初始声明时提供的默认值。PHP 并不额外记录任何静态变量的声明时提供的初始默认值。
同样的情况也发生于测试内部新加载/声明的类的静态属性上。它们也无法在测试结束之后复原为声明时提供的原始默认值,因为无从得知这些默认值。这些被修改过的值会泄漏到后继测试中。
对单元测试而言,推荐在 `setUp()` 中显式的重置测试中使用到的静态属性(最好同时在 `tearDown()` 中执行重置,这样就保证不会影响到后继的测试)。
可以提供黑名单来将静态属性从备份与还原操作中排除出去:
~~~
class MyTest extends PHPUnit_Framework_TestCase
{
protected $backupStaticAttributesBlacklist = array(
'className' => array('attributeName')
);
// ...
}
~~~
>[info] ### Note
> 在方法(例如 `setUp()` )内对 `$backupStaticAttributesBlacklist` 属性进行设置是无效的。
- PHPUnit 手册
- 1. 安装 PHPUnit
- 需求
- PHP 档案包 (PHAR)
- Composer
- 可选的组件包
- 2. 编写 PHPUnit 测试
- 测试的依赖关系
- 数据供给器
- 对异常进行测试
- 对 PHP 错误进行测试
- 对输出进行测试
- 错误相关信息的输出
- 3. 命令行测试执行器
- 命令行选项
- 4. 基境(fixture)
- setUp() 多 tearDown() 少
- 变体
- 基境共享
- 全局状态
- 5. 组织测试
- 用文件系统来编排测试套件
- 用 XML 配置来编排测试套件
- 6. 有风险的测试
- 无用测试
- 意外的代码覆盖
- 测试执行期间产生的输出
- 测试执行时长的超时限制
- 全局状态篡改
- 7. 未完成的测试与跳过的测试
- 未完成的测试
- 跳过测试
- 用 @requires 来跳过测试
- 8. 数据库测试
- 数据库测试所支持的供应商
- 数据库测试的难点
- 数据库测试的四个阶段
- PHPUnit 数据库测试用例的配置
- 理解 DataSet(数据集)和 DataTable(数据表)
- 数据库连接 API
- 数据库断言 API
- 常见问题(FAQ)
- 9. 测试替身
- Stubs (桩件)
- 仿件对象(Mock Object)
- Prophecy
- 对特质(Trait)与抽象类进行模仿
- 对 Web 服务(Web Services)进行上桩或模仿
- 对文件系统进行模仿
- 10. 测试实践
- 在开发过程中
- 在调试过程中
- 11. 代码覆盖率分析
- 用于代码覆盖率的软件衡量标准
- 包含与排除文件
- 略过代码块
- 指明要覆盖的方法
- 边缘情况
- 12. 测试的其他用途
- 敏捷文档
- 跨团队测试
- 13. Logging (日志记录)
- 测试结果 (XML)
- 测试结果 (TAP)
- 测试结果 (JSON)
- 代码覆盖率 (XML)
- 代码覆盖率 (TEXT)
- 14. 扩展 PHPUnit
- 从 PHPUnit_Framework_TestCase 派生子类
- 编写自定义断言
- 实现 PHPUnit_Framework_TestListener
- 从 PHPUnit_Extensions_TestDecorator 派生子类
- 实现 PHPUnit_Framework_Test
- A. 断言
- assertArrayHasKey()
- assertClassHasAttribute()
- assertArraySubset()
- assertClassHasStaticAttribute()
- assertContains()
- assertContainsOnly()
- assertContainsOnlyInstancesOf()
- assertCount()
- assertEmpty()
- assertEqualXMLStructure()
- assertEquals()
- assertFalse()
- assertFileEquals()
- assertFileExists()
- assertGreaterThan()
- assertGreaterThanOrEqual()
- assertInfinite()
- assertInstanceOf()
- assertInternalType()
- assertJsonFileEqualsJsonFile()
- assertJsonStringEqualsJsonFile()
- assertJsonStringEqualsJsonString()
- assertLessThan()
- assertLessThanOrEqual()
- assertNan()
- assertNull()
- assertObjectHasAttribute()
- assertRegExp()
- assertStringMatchesFormat()
- assertStringMatchesFormatFile()
- assertSame()
- assertStringEndsWith()
- assertStringEqualsFile()
- assertStringStartsWith()
- assertThat()
- assertTrue()
- assertXmlFileEqualsXmlFile()
- assertXmlStringEqualsXmlFile()
- assertXmlStringEqualsXmlString()
- B. 标注
- @author
- @after
- @afterClass
- @backupGlobals
- @backupStaticAttributes
- @before
- @beforeClass
- @codeCoverageIgnore*
- @covers
- @coversDefaultClass
- @coversNothing
- @dataProvider
- @depends
- @expectedException
- @expectedExceptionCode
- @expectedExceptionMessage
- @expectedExceptionMessageRegExp
- @group
- @large
- @medium
- @preserveGlobalState
- @requires
- @runTestsInSeparateProcesses
- @runInSeparateProcess
- @small
- @test
- @testdox
- @ticket
- @uses
- C. XML 配置文件
- PHPUnit
- 测试套件
- 分组
- 为代码覆盖率包含或排除文件
- Logging (日志记录)
- 测试监听器
- 设定 PHP INI 设置、常量、全局变量
- 为 Selenium RC 配置浏览器
- D. 升级
- E. 索引
- F. 参考书目
- G. 版权