PHPUnit在测试函数中模拟私有方法

时间:2011-08-19 22:38:02

标签: php mocking phpunit

编写已编写代码的单元测试有时很有趣。

我正在编写以下代码的测试用例(示例):

<?php

class mockPrivate {

    public static function one($a){
        $var = static::_two($a);
        return $var;
    }

    private static function _two($a){
        return $a+1;
    }
}
?>

测试类是这样的:

<?php

require_once 'mockPvt.php';

class mockPrivate_test extends PHPUnit_Framework_TestCase {
    public $classMock;
    protected function setUp(){ 
         $this->classMock = $this->getMock('mockPrivate', array('_two'));
    }

    public function test_one(){
        $a = 1;
        $retVal = 2;
        $classmock = $this->classMock;
        $classmock::staticExpects($this->once())
            ->method('_two')
            ->with($a)
            ->will($this->returnValue($retVal));
        $value = $classmock::one($a);
        $this->assertEquals($value, $retVal);                
    }    
}

?>

$ phpunit mockPrivate_test.php之后运行时出现此错误:

PHP Fatal error:  Call to private method Mock_mockPrivate_531a1619::_two() from context 'mockPrivate' in /data/www/dev-sumit/tests/example
s/mockPvt.php on line 6

但如果我改变了

private    static function _two() 
to 
public     static function _two() or 
protected  static function _two() 

它完全正常。由于这是遗留代码,因此我无法更改private to public/protected。那么有什么办法我可以测试一个函数或者这是phpunit的限制吗?

3 个答案:

答案 0 :(得分:2)

另一种选择是创建一个扩展mockPrivate的类,允许访问您想要测试的对象。你的工程师应该长时间地思考为什么某些东西是私有的(因为这意味着这个类不容易扩展)。还要记住,如果需要覆盖它返回的内容,可以模拟测试类。

class Test_MockPrivate extends MockPrivate
{
    /**
     * Allow public access to normally protected function
     */
    public static function _two($a){
        return parent::_two($a);
    }
}

// Code to force the return value of a now public function
$mock = $this->getMock('Test_MockPrivate', array('_two'));
$mock->expects($this->any())
    ->method('_two')
    ->will($this->returnValue('Some Overridden Value');

答案 1 :(得分:1)

您可以使用反射来更改方法的可见性。您可以在中找到更多信息 PHP object, how to reference?

答案 2 :(得分:0)

使用模拟和反射...(发布此解决方案,因为这是google的最佳结果)

$oMock = $this->getMock("Your_class", array('methodToOverride'));
$oMock->expects( $this->any() )
    ->method('methodToOverride')
    ->will( $this->returnValue( true ) );

$oReflection = new ReflectionClass("Your_Class");

$oMethod = $oReflection->getMethod('privateMethodToInvoke');
$oMethod->setAccessible( true );
$oMethod->invoke( $oMock );