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

不使用PHPUnit测试受保护/私有方法时的代码覆盖率,php,unit-testing,phpunit,code-coverage,Php,Unit Testing,Phpunit,Code Coverage,我知道可以使用反射或其他解决方法使用PHPUnit测试私有/受保护的方法 但是大多数资料告诉我,在类内部为私有方法编写测试不是最佳实践 你应该像测试一个“黑匣子”一样测试这个类——你只是通过比较输入和输出来测试预期的行为,而不考虑内部机制。为类编写测试还应该通过显示缺少代码覆盖率来通知您使用未使用的私有方法 当我测试我的类并生成一个HTML报告时,它会显示测试未涵盖的私有方法,即使调用它们的行是绝对执行/覆盖的。我知道私有方法是被执行的,因为如果它们不是,我的类上的断言就不会通过 这是PHPUn

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

但是大多数资料告诉我,在类内部为私有方法编写测试不是最佳实践

你应该像测试一个“黑匣子”一样测试这个类——你只是通过比较输入和输出来测试预期的行为,而不考虑内部机制。为类编写测试还应该通过显示缺少代码覆盖率来通知您使用未使用的私有方法

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

这是PHPUnit中的预期行为吗?我可以争取100%的覆盖率,而仍然只是间接地测试私有方法吗

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

公共功能显示为“覆盖”,私人功能间接覆盖,但在PHPUnit报告中显示为红色

测试:


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

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

您可以这样做:

    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());
        }

    }

希望这有助于

测试私有方法本身并不是一个问题-做这样的测试并不是一个坏做法。首先,私有方法被认为是有害的,因为它们很难测试。@narf,我不同意这一点。测试私有方法是为了进行脆性测试,如果你认为你唯一的选择是通过反射进行测试,我会认为它是一种坏代码气味。私有方法是无害的,它们是在类中组织代码的好方法。@SamHolder Brittle总比没有好。。。把考试定为不好的做法是没有道理的,你也无法说服我无论如何,测试什么、如何以及测试到什么程度在很大程度上是一个基于观点的话题,所以我宁愿同意你的观点。:)@narf您应该基于可公开验证的行为进行测试。私有方法是一个实现细节。@narf遗憾的是,您在这个问题上思想封闭。你似乎认为我的立场是“不要在私有方法中测试代码”,而实际上是“通过公共方法测试所有代码”。如果您碰巧将其中一些代码放在了由公共方法调用的私有方法中,那就好了。不相关,但很好。请看我的答案和Hi@SamHolder当然,问题是关于代码覆盖率,所以我回答如何忽略/欺骗代码覆盖率。是的,细节中的方法可以封装在一个简单的util类中,该类应该在一个独立的作用域中进行单元测试。我不是在评论你的答案的质量,这很可能是完美的,更多的是,如果这是一个解决方案,那么G*d将帮助所有PHP开发人员。@SamHolder,对不起,我对单元测试是新手。我欢迎任何建议,但PHPUnit文档专门使用covers注释进行覆盖率报告。还是你认为有更好的方法?此外,是的,我很乐意放弃PHP/Symfony,转而选择Haskell/Snap这样的功能性工具,但在现实世界中,你在拥有大量廉价初级开发人员的大型团队中工作,而且90%的web开发都是在滥用的PHP框架中编写的肮脏代码,没有任何形式的规划或文档。但是我很想看到“正确”的答案,因为您也发表了支持在类内部使用私有方法的评论;)@Feroxium我不是一个PHP开发人员,只是一个单元测试的倡导者,如果这是PHP能提供的最好的东西,那么我的建议是学习c#、java、python、ruby或其他非PHP的东西。我怀疑所有这些支付方式都和PHP一样好,而函数式语言的支付方式甚至更好。
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());
    }

}
    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());
        }

    }