Php,克隆对象,添加新方法或覆盖它们

时间:2014-06-25 20:04:07

标签: java php object mocking

出于测试目的,我试图"假的"一些对象。我想做以下事情:我有一个对象,想要添加新方法,或者覆盖一些。可悲的是,与Java不同,它不可能创造出无名的"类。好吧,我可以通过简单地创建一个新类来实现它,但我想做它dinamicaly。

这是班级:

class Test
{
    public function method1()
    {
        return 'oldmethod1';
    }
    public function method2()
    {
        return 'oldmethod2';
    }
    public static function staticmethod1()
    {
        return 'staticmethod1';
    }
    public static function staticmethod2()
    {
        return 'staticmethod2';
    }
}

现在我想做什么:

$a = new Test();

$b = new CreateMockObjectFromObject($a);
$b->newmethod = function() { return 'newmethod'; };
$b->method2 = function() { return 'method2 is overwritten'; };
$b->staticmethod2 = function() { return 'staticmethod2 overwritten'; };

echo $b->method1().'<br>';
echo $b->method2().'<br>';
echo $b::staticmethod1().'<br>';
echo $b::staticmethod2().'<br>';

在这里你可以看到我的意愿:调用普通方法,覆盖方法,调用静态方法,覆盖方法。结果:失败,成功,失败,失败。

我有一个助手类:

class CreateMockObjectFromObject
{
    private $sourceObj;

    /**
     * @return
     */
    public function __call ($method, $args)
    {
        if (isset($this->sourceObj->$method))
        {
            return call_user_func_array($this->sourceObj->$method, $args);
        }

        if (isset($this->$method))
        {
            return call_user_func_array($this->$method, $args);
        }
        throw new Exception ($method.' NOT FOUND');
    }

    /**
     * @return
     */
    public static function __callStatic ($method, $args)
    {
        // I cant even imagine this...
    }

    /**
     * @return CreateMockObjectFromObject
     */
    public function __construct ($sourceObj)
    {
        $this->sourceObj = $sourceObj;
    }
}

我甚至无法想象静态方法。如何编写这个助手类,以便所有的模拟/伪装都可以工作?我甚至没有谈论&#34; const&#34; -s ...... 再一次,我知道这一切都可以通过扩展完成,但我需要这样做!

1 个答案:

答案 0 :(得分:1)

嘲笑整个班级:

$mock = Mockery::mock('FQ\ClassName');

仅模拟某些方法:

$mock = Mockery::mock('FQ\ClassName[method1, method2]')

这里,method3,method4,...,methodN的功能与在类实现中完全相同。

期待:

$mock->shouldReceive('method1')
    ->once()
    ->andReturn('a value')
;

在您做出期望之后,然后根据被测系统采取行动:

$return = $objectImTesting->performAction($mock);

一旦你采取行动,根据你提供的输入,你应断言任何回报值应该是它应该是:

$this->assertEquals('a value', $return);

采用上面的例子,如果满足以下任何条件,测试将失败:

  • 模拟对象上的method1永远不会被调用
  • 模拟对象上的method1被多次调用
  • performAction的返回值不是文字值'a value'

现在,你还没有重新发明轮子,而是已经开始编写测试了。同样免费,您可以获得PHPUnit和Mockery为您提供的所有内容(您认为在您的模拟框架中能够支持Demeter Chains需要多长时间?)。

不要误会我的意思,如果您感兴趣的是学习,请务必继续开发您的测试框架。但是,在我看来,我不想相信我自己开发的测试框架,以确保我编写的代码有效。我宁愿使用一些开源的东西,并且已经存在了一段时间,以便我晚上可以睡得更轻松。

更多信息: