不使用 PHPUnit 测试 protected/private 方法时的代码覆盖率

Code coverage when not testing protected/private methods with PHPUnit

我知道可以使用 PHPUnit 使用反射或其他变通方法测试 private/protected 方法。

但是大多数消息来源告诉我,不是最佳做法是在 class 中为私有方法编写测试。

您应该像 "black box" 一样测试 class — 您只需通过比较输入和输出来测试预期行为,而忽略内部机制。为 classes 编写测试还应该通过显示缺少代码覆盖率来通知您未使用的私有方法。

当我测试我的 class 并生成 HTML 报告时,它显示私有方法未被测试覆盖,即使调用它们的行绝对是 executed/covered.我知道私有方法已执行,因为如果它们不是,我的 class 上的断言将不会通过。

这是 PHPUnit 中的预期行为吗?我能否争取 100% 的覆盖率,同时仍然仅间接地测试私有方法?

一些简化的示例代码(在 Symfony2 中使用 RestBundle):

class ApiController extends FOSRestController {

/*
 * @REST\View()
 * @REST\Get("/api/{codes}")
 */
public function getCodesAction($codes) {
    $view = new View();
    $view->setHeader('Access-Control-Allow-Origin', '*');
    $view->setData(array('type' => 'codes','data' => $this->_stringToArray($codes)));
    $view->setFormat('json')->setHeader('Content-Type', 'application/json');
    return $this->handleView($view);
}

private function _stringToArray($string){
    return explode('+',$string);
}

public函数显示为"covered",私有函数被间接覆盖,但在PHPUnit报告中显示为红色。

测试:

class ApiControllerTest extends WebTestCase {

    public function test_getCodesAction(){
        $client = static::createClient();
        $client->request('GET', '/api/1+2+3');
        $this->assertContains('{"type": "codes", "data": [1,2,3]}', $client->getResponse()->getContent());
    }

}

这当然只是一个愚蠢的例子,我也可以在 public 函数中包含 explode() ;但是我正在为其编写测试的控制器包含更复杂和可重用的私有函数,这些函数以更复杂的方式转换数据(但仍然没有副作用)。

在 Phpunit 中,您可以使用特殊注释指定涵盖的方法,如 doc 中所述。

你可以这样做:

    class ApiControllerTest extends WebTestCase {

        /**
         * @covers ApiController::getCodesAction
         * @covers ApiController::_stringToArray
         */
        public function test_getCodesAction(){
            $client = static::createClient();
            $client->request('GET', '/api/1+2+3');
            $this->assertContains('{"type": "codes", "data": [1,2,3]}', $client->getResponse()->getContent());
        }

    }

希望对您有所帮助