【问题标题】:How to unit-test protected methods?如何对受保护的方法进行单元测试?
【发布时间】:2017-06-24 23:45:34
【问题描述】:

有没有办法对类的受保护或私有方法进行单元测试?就像现在一样,我公开了很多方法以便能够测试它们,这破坏了 API。

编辑:实际上在这里回答:Best practices to test protected methods with PHPUnit

【问题讨论】:

    标签: phpunit


    【解决方案1】:

    您可以通过使用ReflectionMethod 类后跟invoke 方法来访问您的私有和/或受保护方法,但是要调用该方法,您还需要您的类的实例,这在某些情况下是不可能的。基于这个很好的例子是这个:

    模拟你的班级:

    $mockedInstance = $this->getMockBuilder(YourClass::class)
            ->disableOriginalConstructor()    // you may need the constructor on integration tests only
            ->getMock();
    

    让你的方法被测试:

    $reflectedMethod = new \ReflectionMethod(
        YourClass::class,
        'yourMethod'
    );
    
    $reflectedMethod->setAccessible(true);
    

    调用您的私有/受保护方法:

    $reflectedMethod->invokeArgs(    //use invoke method if you don't have parameters on your method
        $mockedInstance, 
        [$param1, ..., $paramN]
    );
    

    【讨论】:

    • 感谢您拯救了我的一天。对于私人方法,它对我来说就像魅力一样。
    • 虽然,测试私有方法并不是一个好习惯。只是因为某个点的私有方法会被公有方法调用,那么这个公有方法应该是被测试的。无论如何,每种情况都是不同的情况。 :+1
    • 是的,不测试私有函数是有意义的。
    【解决方案2】:

    对于受保护的方法,您可以对被测类进行子类化:

    class Foo 
    {
        protected function doThings($foo) 
        {
            //...
        }
    }
    
    
    class _Foo extends Foo 
    {
        public function _doThings($foo) 
        {
            return $this->doThings($foo);
        }
    } 
    

    在测试中:

    $sut = new _Foo();
    $this->assertEquals($expected, $sut->_doThings($stuff));
    

    使用私有方法有点困难,您可以使用反射 API 来调用受保护的方法。此外,还有一个论点是私有方法应该只在重构过程中出现,因此应该被调用它们的公共方法所覆盖,但只有在您首先进行测试并且在现实生活中我们有遗留代码时才真正有效处理;)

    反射 api 的链接:

    http://php.net/manual/en/reflectionmethod.setaccessible.php

    此外,此链接看起来对此很有用:

    https://jtreminio.com/2013/03/unit-testing-tutorial-part-3-testing-protected-private-methods-coverage-reports-and-crap/

    【讨论】:

    • PSR-2 不接受将两个类放在一个文件中。所以我不确定子类化是一个很好的选择。感谢您的反思提示。
    • 完全正确,在同一个“文件”中使用它仅用于演示目的......事实上,使用 PHP 7 将是一个匿名类的好用途......
    猜你喜欢
    • 2010-11-10
    • 1970-01-01
    • 2015-02-26
    • 2012-02-22
    • 2021-05-31
    • 2020-09-23
    • 2017-05-04
    • 2012-05-22
    • 2019-05-07
    相关资源
    最近更新 更多