关于php:不使用PHPUnit测试受保护/私有方法时的代码覆盖率

Code coverage when not testing protected/private methods with PHPUnit

我知道可以使用反射或其他解决方法使用PHPUnit测试私有/受保护的方法。

但是大多数消息来源告诉我,在类中编写私有方法的测试并不是最好的做法。

您应该将类??测试为"黑盒子" - 您只需通过将输入与输出进行比较而不考虑内部机制来测试预期行为。编写类的测试还应通过显示缺少代码覆盖率来通知您未使用的私有方法。

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}

公共函数显示为"覆盖",私有函数是间接覆盖的,但在PHPUnit报告中显示为红色。

测试:

1
2
3
4
5
6
7
8
9
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());
    }

}

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


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

你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
    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());
        }

    }

希望这有帮助