例 2.1: 用 PHPUnit 测试数组操作
<?php
class StackTest extends PHPUnit_Framework_TestCase{
public function testPushAndPop()
{
$stack = array();
$this->assertEquals(0, count($stack));
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertEquals(1, count($stack));
$this->assertEquals('foo', array_pop($stack));
$this->assertEquals(0, count($stack));
}
}?>
| 单元测试主要是作为一种良好实践来编写的,它能帮助开发人员识别并修复 bug、重构代码,还可以看作被测软件单元的文档。要实现这些好处,理想的单元测试应当覆盖程序中所有可能的路径。一个单元测试通常覆盖一个函数或方法中的一个特定路径。但是,测试方法并不一定非要是一个封装良好的独立实体。测试方法之间经常有隐含的依赖关系暗藏在测试的实现方案中。 |
|
| --Adrian Kuhn et. al. |
PHPUnit支持对测试方法之间的显式依赖关系进行声明。这种依赖关系并不是定义在测试方法的执行顺序中,而是允许生产者(producer)返回一个测试基境(fixture)的实例,并将此实例传递给依赖于它的消费者(consumer)们。
例 2.2 展示了如何用 @depends
标注来表达测试方法之间的依赖关系。
例 2.2: 用 @depends
标注来表达依赖关系
<?php
class StackTest extends PHPUnit_Framework_TestCase{
public function testEmpty()
{
$stack = array();
$this->assertEmpty($stack);
return $stack;
}
/**
* @depends testEmpty
*/
public function testPush(array $stack)
{
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertNotEmpty($stack);
return $stack;
}
/**
* @depends testPush
*/
public function testPop(array $stack)
{
$this->assertEquals('foo', array_pop($stack));
$this->assertEmpty($stack);
}
}
?>
在上例中,第一个测试, testEmpty()
,创建了一个新数组,并断言其为空。随后,此测试将此基境作为结果返回。第二个测试,testPush()
,依赖于 testEmpty()
,并将所依赖的测试之结果作为参数传入。最后, testPop()
依赖于 testPush()
。
为了快速定位缺陷,我们希望把注意力集中于相关的失败测试上。这就是为什么当某个测试所依赖的测试失败时,PHPUnit 会跳过这个测试。通过利用测试之间的依赖关系,缺陷定位得到了改进,如例 2.3中所示。
例 2.3: 利用测试之间的依赖关系
<?php
class DependencyFailureTest extends PHPUnit_Framework_TestCase{
public function testOne()
{
$this->assertTrue(FALSE);
}
/**
* @depends testOne
*/
public function testTwo()
{
}
}
?>
phpunit --verbose DependencyFailureTestPHPUnit 4.2.0 by Sebastian Bergmann.
FS
Time: 0 seconds, Memory: 5.00Mb
There was 1 failure:
1) DependencyFailureTest::testOne
Failed asserting that false is true.
/home/sb/DependencyFailureTest.php:6
There was 1 skipped test:
1) DependencyFailureTest::testTwo
This test depends on "DependencyFailureTest::testOne" to pass.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1, Skipped: 1.
测试可以使用多于一个 @depends
标注。PHPUnit 不会更改测试的运行顺序,因此你需要自行保证某个测试所依赖的所有测试均出现于这个测试之前。
拥有多个 @depends
标注的测试,其第一个参数是第一个生产者提供的基境,第二个参数是第二个生产者提供的基境,以此类推。参见例 2.4。
例 2.4: 有多重依赖的测试
<?php
class MultipleDependenciesTest extends PHPUnit_Framework_TestCase{
public function testProducerFirst()
{
$this->assertTrue(true);
return 'first';
}
public function testProducerSecond()
{
$this->assertTrue(true);
return 'second';
}
/**
* @depends testProducerFirst
* @depends testProducerSecond
*/
public function testConsumer()
{
$this->assertEquals( array('first', 'second'),
func_get_args()
);
}
}
?>
phpunit --verbose MultipleDependenciesTestPHPUnit 4.2.0 by Sebastian Bergmann.
...
Time: 0 seconds, Memory: 3.25Mb
OK (3 tests, 3 assertions)