如何使用PHPUnit获得100%的代码覆盖率

如何使用PHPUnit获得100%的代码覆盖率,php,unit-testing,zend-framework,phpunit,Php,Unit Testing,Zend Framework,Phpunit,我正在编写一个Zend框架应用程序,并使用PHPUnit对其进行单元测试。总的来说,事情进展顺利,但是我在PHPUnit和代码覆盖率方面遇到了一个小问题,但很恼人——它有时会告诉我某一行没有经过测试,我不知道如何强制测试 例如,在下面的代码中,我启动了两个测试:一个带有GET请求,一个带有POST请求。测试通过了,一切正常。但是,当我查看代码覆盖率时,它显示没有执行“else”行 public function editAction() { if ($request-&g

我正在编写一个Zend框架应用程序,并使用PHPUnit对其进行单元测试。总的来说,事情进展顺利,但是我在PHPUnit和代码覆盖率方面遇到了一个小问题,但很恼人——它有时会告诉我某一行没有经过测试,我不知道如何强制测试

例如,在下面的代码中,我启动了两个测试:一个带有GET请求,一个带有POST请求。测试通过了,一切正常。但是,当我查看代码覆盖率时,它显示没有执行“else”行

public function editAction()
{        
    if ($request->isPost()) {
        // do actions related to POST
    } else {
        // do action related to GET
    }
}
有什么想法吗?作为一个附带问题,您通常会坚持进行单元测试直到获得100%的代码覆盖率吗?或者这真的不实际


非常感谢……

几年前,通过ZF 1.0的发布,我是Zend框架的项目负责人。我非常努力地提高所有组件的测试覆盖率,我们有一项政策,即组件必须具有一定的最低代码覆盖率,才能从孵化器引入ZF

然而,您是对的,试图从所有类的测试中获得100%的代码覆盖率并不实际。ZF中的一些类具有100%的覆盖率,但对于这些类,以下一个或多个是正确的:

  • 这门课非常简单
  • 这些测试花了大量的时间来编写。例如,复杂的设置代码,用于创建条件,以练习所有模糊的拐角情况。看看我写的Zend_Db的单元测试!尽管强迫自己测试这些极端情况是有益的,因为我保证它会引导您找到需要修复的代码
  • 必须对类进行重构,使其更“可测试”。不管怎样,这通常是一件好事,因为您最终得到了更好的OO代码、更少的耦合、更少的静态元素等等。请参阅Zend_日志的类和测试
但我们也意识到100%的代码覆盖率有时是人为的目标。尽管如此,实现较少100%覆盖率的测试套件仍然是足够的。而且,一个覆盖率达到100%的测试套件并不一定能保证质量

下面的函数很容易获得100%的代码覆盖率。但是我们测试过零除吗

function div($numerator, $denominator) {
    return $numerator / $denominator;
}

因此,您应该将代码覆盖率作为测试的一个指标,而不是最终目标。

如果这就是您测试的全部内容,那么我会假设您的测试:

在这种情况下,我看不出有什么理由不容易获得100%的代码覆盖率

但是,是的:测试Zend Framework控制器是相当困难的,在某个时候,您必须非常努力地从控制器中获取所有的应用程序逻辑,或者直接使用它

但是,同样的情况不适用于您的车型。即使在ZF应用程序中,这些测试也应该非常容易

代码覆盖的目的是告诉您代码库的哪些部分甚至没有被执行。它不会告诉您真正测试的是什么,只能作为了解测试套件质量的“最低要求”(如果您不使用@covers,甚至可能会欺骗您)


简言之:如果您有大型控制器和不太容易更改的体系结构,只需使用经过测试的控制器进行设置,但不要将相同的逻辑应用于您的模型。ZF中的任何内容都不会阻止您正确地测试这些代码,您只有注释的代码才是最重要的。如果一个块的右大括号可能一直到最后,它将在代码覆盖率报告中显示为可执行文件。寻找一个你没有实际测试的分支

if ($request->isPost()) {
    if ($x < 5) {
        return '<';
    }
    elseif ($x > 5) {
        return '>';
    }
    // Do you have a test for $x == 5?
}
if($request->isPost()){
如果($x<5){
返回“”;
}
//你们有$x==5的测试吗?
}
至于100%代码覆盖率的目标,我完全同意比尔的观点。对于我编写的一些框架类,我将努力实现100%,但我知道这并不意味着我已经真正测试了所有的可能性。通常,当我发现自己过度努力以实现100%的覆盖率时,很可能是强迫症发作了。:)


只是。一。更多测试

谢谢大卫,你成功了。我真的很欣赏Bill和edorian对代码覆盖率的观点,但是你关于“跌破到最后”的评论将帮助我确定那些“不稳定”的地方!这里要补充一点。当您使用改变控制流的助手方法时,经常会发生这种情况,例如调用
exit()
或抛出异常的方法。代码覆盖工具不知道所述函数永远不会将控制权返回给调用方。我将向PHPCC提交一个增强请求,请求添加
@neverReturns
方法注释,但我怀疑Sebastian是否会同意。
if ($request->isPost()) {
    if ($x < 5) {
        return '<';
    }
    elseif ($x > 5) {
        return '>';
    }
    // Do you have a test for $x == 5?
}