【问题标题】:How to get 100% Code Coverage with PHPUnit如何使用 PHPUnit 获得 100% 的代码覆盖率
【发布时间】:2014-02-22 04:28:10
【问题描述】:

我正在编写一个 Zend Framework 应用程序并使用 PHPUnit 对其进行单元测试。总的来说,事情进展顺利,但是我有一个关于 PHPUnit 和代码覆盖率的小而烦人的问题 - 它有时告诉我没有测试特定的行,我不知道如何强制它进行测试。

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

public function editAction()
{        
    if ($request->isPost()) {
        // do actions related to POST
    } else {
        // do action related to GET
    }
}

有什么想法吗?作为一个附带问题,您是否通常会坚持进行单元测试,直到获得 100% 的代码覆盖率?或者这真的不实用?

非常感谢...

【问题讨论】:

    标签: php unit-testing zend-framework phpunit


    【解决方案1】:

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

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

    • 课程非常简单。
    • 编写这些测试需要付出非凡的努力。例如。复杂的设置代码为执行所有晦涩的极端情况创造条件。查看我为 Zend_Db 编写的单元测试!尽管强迫自己测试这些极端情况是有益的,因为我保证它会引导您找到需要修复的代码。
    • 必须重构该类以使其更“可测试”。无论如何,这通常是一件好事,因为您最终会得到更好的 OO 代码、更少的耦合、更少的静态元素等。请参阅 Zend_Log 的类和测试。

    但我们也意识到 100% 的代码覆盖率有时是人为的目标。然而,达到 100% 覆盖率的测试套件可能就足够了。覆盖率达到 100% 的测试套件不一定能保证质量。

    以下函数很容易获得 100% 的代码覆盖率。但是我们是否测试了除以零?

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

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

    【讨论】:

      【解决方案2】:

      只有 cmets 的代码才是最重要的。如果块的右大括号有可能出现在代码覆盖率报告中,它将显示为可执行文件。寻找一个你实际上并没有测试的分支。

      if ($request->isPost()) {
          if ($x < 5) {
              return '<';
          }
          elseif ($x > 5) {
              return '>';
          }
          // Do you have a test for $x == 5?
      }
      

      关于 100% 的代码覆盖率目标,我完全同意 Bill。对于我编写的一些框架类,我会努力做到 100%,但我知道这并不意味着我已经真正测试了每一种可能性。通常,当我发现自己为了达到 100% 的覆盖率而努力工作时,很可能是强迫症开始了。:)

      只是。 . .一 。 . .更多的 。 . .测试 。 . .

      【讨论】:

      • 谢谢大卫,你搞定了。我真的很欣赏 Bill 和 edorian 对代码覆盖率的看法,但是您关于“坚持到底”的评论将帮助我确定那些令人讨厌的“无法测试”的部分!
      • 这里要补充一点。当您使用改变控制流的辅助方法(例如调用exit() 或抛出异常的方法)时,这种情况经常发生。代码覆盖率工具不知道所述函数永远不会将控制权返回给调用者。我将向 PHPCC 提交增强请求以获取 @neverReturns 方法注释,但我怀疑 Sebastian 是否会这样做。
      【解决方案3】:

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

      class UserControllerTest extends Zend_Test_PHPUnit_ControllerTestCase {
          // [...]
          public function testSomething()
          {
              $this->request
                   ->setMethod('POST')
                   ->setPost(array(
                       'username' => 'foobar',
                       'password' => 'foobar'
                   ));
              $this->editAction();
              // assertThatTheRightThingsHappend
          }
      }
      

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

      但是是的:测试 Zend 框架控制器非常困难,有时您必须非常努力地从控制器中获取所有应用程序逻辑,或者只是忍受它。

      同样的事情不适用于您的模型。这些应该很容易测试,即使在 ZF 应用程序中也是如此。

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

      简而言之:如果您有大型控制器,并且架构不太容易更改,只需使用某某经过测试的控制器进行设置,但不要将相同的逻辑应用于您的模型。 ZF 中没有任何东西可以阻止您正确测试这些

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-02-26
        • 2017-12-07
        • 2012-05-04
        • 2016-02-25
        • 2012-08-04
        • 2013-09-12
        • 1970-01-01
        相关资源
        最近更新 更多