【问题标题】:Mock private method in a test function by PHPUnitPHPUnit 在测试函数中模拟私有方法
【发布时间】:2011-10-30 23:37:36
【问题描述】:

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

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

<?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的限制?

【问题讨论】:

标签: php mocking phpunit


【解决方案1】:

另一种选择是创建一个扩展 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');

【讨论】:

  • 谢谢迈克。我没有时间对此进行测试,但想知道,我们可以使用新的 PHPUnit 3.6 模拟私有函数吗?
  • @Sumitk 看起来他们不能在 3.7 中模拟私有,请参阅:phpunit.de/manual/3.7/en/test-doubles.html"限制请注意,最终、私有和静态方法不能被存根或模拟。它们被 PHPUnit 的测试双重功能忽略并保留他们原来的行为。”
  • 别忘了,受保护的方法也不能被模拟。
【解决方案2】:

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

【讨论】:

  • Reflection 的setAccessible() 只允许您通过反射对象从类外部调用该方法。它不会改变不能覆盖模拟所需的方法这一事实。
  • @David - 我认为私有不能被嘲笑,因为在这种情况下它不能被覆盖。那么每个使用 phpunit 的人都会在调用私有函数的地方留下那个函数部分吗?我确实找到了这个链接 - link 人们已经修改了框架以支持私有测试。我会试试的。感谢您的评论!
  • @Sumitk - 你可以使用setAccessible()test 私有方法(虽然很多人会说这不是一个好主意),但是为了嘲笑你就不走运了。在测试调用它的方法时,您可以将其更改为受保护或不模拟。
【解决方案3】:

使用模拟和反射...(发布此解决方案,因为这是谷歌搜索结果)

$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 );

【讨论】:

  • 这不是我们所要求的。
猜你喜欢
  • 2016-01-30
  • 1970-01-01
  • 2022-08-05
  • 1970-01-01
  • 2016-06-12
  • 2014-12-13
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多