PHP单元测试,带模拟的受保护方法

Posted

技术标签:

【中文标题】PHP单元测试,带模拟的受保护方法【英文标题】:Php unit testing, protected method with mocking 【发布时间】:2013-10-10 02:19:50 【问题描述】:

我是 TDD 新手。我被困在一些单元测试中...请看一下我的代码...提前谢谢...

class Parser

    protected function _checkCurlExistence()
    
        // Unable to to mock function_exists, thats why fallback with this method

        return function_exists('curl_version');
    


    public function checkCurlExtension()
    

        // I want to test 2 situations from this method...
        // 1. if curl extension exists
        // 2. or when curl extension does not exists...throw error

        if($this->_checkCurlExistence() === false)

            try
                throw new CurlException(); //Some curl error handler exception class
            catch(CurlException $error)
                exit($error->getCurlExtensionError());
            

        

        return true;
    

想测试:

class ParserTest

    /**
    * @expectedException CurlException
    */
    public function testCheckCurlExtensionDoesNotExists()
    
        //Some testing code with mocking...
    

    public function testCheckCurlExtensionExists()
    
       //Some testing code with mocking..and assertion 

    


我的问题/请求:

请您填写这些测试。我永远被困在这上面……无法继续我的 TDD 之旅。

一些步骤(您可以跳过这些行):

我已尽力自己解决此问题,但无法解决。有些步骤是..

我尝试了 phpunit 的原生 mockerypadraic/mockery (git)、codeception/aspect-mock (git) 来模拟 _checkCurlExistence() 两种情况的方法...我不确定我是否做得对...这就是为什么,不发布那些代码...

我尝试了 Reflection Api,通过 ma​​gic method __call()... 将受保护方法动态转换为公共方法以帮助模拟...

我也做了很多谷歌搜索。了解最佳实践是仅测试公共方法。但是我的公共方法依赖于受保护的方法......所以我该如何测试???

【问题讨论】:

我更愿意通过 checkCurlExtension() 对其进行测试,我的意思是如果找不到扩展名,它会抛出异常。在您的测试用例中使用它。 F.e $this->setExpectedException("CurlException");你就完成了。那将是在您删除“exit()”函数之后。只是利用例外来发挥你的优势 如果你想测试一个受保护/私有的方法,你可以用一个特殊的测试类来扩展这个类,公开这些方法? 不应测试受保护/私有方法。 【参考方案1】:

找到了一种模拟 php 内置函数的方法 PHPUnit function mocker extension

所以我现在可以轻松测试这 2 个场景。

namespace 'myNameSpace';

class Parser

    public function checkCurlExtension()
    
        // I want to test 2 situations from this method...
        // 1. if curl extension exists
        // 2. or when curl extension does not exists...throw error

        if(function_exists('curl_version') === false)
            throw new CurlException(); //Some curl error handler exception class
        

        return true;
    




class ParserTest

    private $parser;

    /**
    * @expectedException CurlException
    */
    public function testCheckCurlExtensionDoesNotExists()
    
        $funcMocker = \PHPUnit_Extension_FunctionMocker::start($this, 'myNameSpace')
        ->mockFunction('function_exists')
        ->getMock();

        $funcMocker->expects($this->any())
        ->method('function_exists')            
        ->will($this->returnValue(false));

        $this->parser->checkCurlExtension(); 

    

    public function testCheckCurlExtensionExists()
    
       //we can do same here...please remember DRY...

    

【讨论】:

以上是关于PHP单元测试,带模拟的受保护方法的主要内容,如果未能解决你的问题,请参考以下文章

受保护插槽的单元测试[关闭]

是否可以在 IOS 的 XCTest 单元测试用例中模拟方法(带参数)调用

带小数的 PHP 和单元测试断言

PHP 单元测试 - 使用 Mockery 模拟静态自动加载类

Python - 访问类的受保护成员_

PHP单元测试模拟成员变量依赖