Contributed by
Grégoire Pineau
in #23149.
Code coverage 是一个标尺,它描述的是程序的源代码被某特定测试组件测试后的级别。代码覆盖率高,即已被彻底测试,包含 bug 的机会就小。PHPUnit提供了 工具来测量 code coverage,但并不足够精确人。
思考下例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class Bar
{
public function barMethod() { return 'bar'; }
}
class Foo
{
private $bar;
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
public function fooMethod()
{
$this->bar->barMethod();
return 'bar';
}
} |
如果你的测试是下面这样:
1 2 3 4 5 6 7 8 9 10 | class FooTest extends PHPUnit\Framework\TestCase
{
public function test()
{
$bar = new Bar();
$foo = new Foo($bar);
$this->assertSame('bar', $foo->fooMethod());
}
} |
PHPUnit 认为一行代码应在执行之后马上得到测试。FooTest::test
执行的是 Foo
和 Bar
类的每一行代码,因此 PHPUnit 所计算出来的代码覆盖率将会是 100%。然而这并不准确,因为 Bar
类并未得到测试。
解决方案是对每一个类使用 PHPUnit 的 @covers
annotation 来指定哪个类是当前测试到的。因此 在 Symfony 3.4 中我们把一个 CoverageListener 添加到了 PHPUnit Bridge 组件中以提供 更佳的 code coverage reports.
你要做的唯一改变,是在 phpunit.xml
配置文件中,让程序一个 CoverageListener
作为 PHPUnit 的一个监听:
1 2 3 4 5 6 7 8 9 | <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.0/phpunit.xsd"
>
<!-- ... -->
<listeners>
<listener class="Symfony\Bridge\PhpUnit\CoverageListener" />
</listeners>
</phpunit> |
此监听检查每一个待测试的类,并做如下事情:
- 若类有一个
@covers
annotation,什么也不做; - 若未找到
@covers
annotation,在这个类中自动寻找测试代码并添加注释。
用于寻找测试代码的逻辑是基于 Symfony 的最佳实践: 测试时使用的是和代码相同的目录结构,再添加一个 Test
后缀到类名中。例如,若测试的类是 My\Namespace\Tests\FooTest
,则相关的类会按照 My\Namespace\Foo
进行猜测。
如果这个猜测逻辑太简单,或在你的程序中无法使用,你可以对 PHPUnit listener 提供自己的解决方案:
1 2 3 4 5 6 7 | <listeners>
<listener class="Symfony\Bridge\PhpUnit\CoverageListener">
<arguments>
<string>App\Test\CoverageSolver::solve</string>
</arguments>
</listener>
</listeners> |