PHPUnit - 创建模拟对象作为属性的存根

17
我正在尝试在PHPUnit中配置一个Mock对象,以便为不同的属性(通过__get函数访问)返回值。
例如:
class OriginalObject {
 public function __get($name){
switch($name)
 case "ParameterA":
  return "ValueA";
 case "ParameterB":
  return "ValueB";
 }
}

我正在尝试使用以下代码进行模拟:

$mockObject = $this->getMock("OrigionalObject");

$mockObject    ->expects($this->once())
    ->method('__get')
    ->with($this->equalTo('ParameterA'))
    ->will($this->returnValue("ValueA"));

$mockObject    ->expects($this->once())
    ->method('__get')
    ->with($this->equalTo('ParameterB'))
    ->will($this->returnValue("ValueB"));

但这个方法失败了 :-(


1
您的模拟代码中的错别字(“Origional”而不是“Original”,ValueA和ValueB缺少闭合引号)是实际代码的一部分,还是转录错误? - Phil
1
LOL,感谢Phil指出我的词汇障碍。现在已经更正了拼写错误,这些错误只存在于示例代码中 - 显然这不是实际执行的代码。 - Tim
2个回答

9

我还没有尝试模拟 __get 方法,但也许这个方法可以实现:

// getMock() is deprecated
// $mockObject = $this->getMock("OrigionalObject");
$mockObject = $this->createMock("OrigionalObject");

$mockObject->expects($this->at(0))
    ->method('__get')
    ->with($this->equalTo('ParameterA'))
    ->will($this->returnValue('ValueA'));

$mockObject->expects($this->at(1))
    ->method('__get')
    ->with($this->equalTo('ParameterB'))
    ->will($this->returnValue('ValueB'));

我已经在测试中使用了$this->at(),它可以正常工作(但不是最优解决方案)。我从这个线程中得到了它:如何让PHPUnit MockObjects根据参数返回不同的值?

嗨,Koen $this->at() 对我有效 - 谢谢 ;-) 你为什么不认为这是最佳解决方案呢? - Tim
1
它并不真正可扩展,而且测试难以阅读。如果您为回调函数命名得当,那么它可能更容易阅读。但首先我会尝试重构__get方法。 - koen
同时,你正在测试状态(一些人认为这是不好的实践),甚至更糟的是,私有状态(许多人认为这是一种不好的实践)。当然,有些聪明的人并不认为这有问题,你可能是其中之一。 - koen

4
这应该可以运行:
class Test extends \PHPUnit_Framework_TestCase {
...
    function testSomething() {
         $mockObject = $this->getMock("OrigionalObject");

         $mockObject
              ->expects( $this->any() )
              ->method('__get')
              ->will( $this->returnCallback('myMockGetter'));
         ...
     }
...
}

function myMockGetter( $classPropertyName ) {
    switch( $classPropertyName ) {
        case 'ParameterA':
            return 'ValueA';

        case 'ParameterB':
            return 'ValueB';
    }
}
... ... 

我认为我的解决方案比koen更优,但他在评论中提出了一些重要的观点。我认为一个可能的解决方案是创建一个测试类,而不是使用模拟对象。这通常用于诸如HTTP适配器之类的东西。 - Johntron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接