你可以在回调中使用$ this来获取phpunit中被模拟类的受保护属性吗?

Kam*_*zic 7 php phpunit unit-testing mocking

你可以在回调中使用$ this来获取phpunit中被模拟类的受保护属性吗?或者还有其他方法可以实现吗?

 $mock = $this->getMock('A', array('foo'));
 $mock->expects($this->any())->method('foo')->will(
     $this->returnCallback(function() {
         return $this->bar;
 }));
Run Code Online (Sandbox Code Playgroud)

如果考虑注入模拟对象,这可能非常有用.有时类对其他类具有硬编码依赖性,但它使用方法创建它,理论上可以模拟和创建模拟对象而不是硬编码对象.请看另一个例子.

class A {
  protected $bar = "bar";

  public function foo () {
    $b = new B();
    return $b->fizz($this->bar);
  }
}

class B {
  public function fizz ($buzz) {
    return $buzz;
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,让我们说B级做坏事,我想用mock替换它.

 $mockB = $this->getMock('B');
 // (...) - and probably mock other things
 $mockA = $this->getMock('A', array('foo'));
 $mockA->expects($this->any())->method('foo')->will(
     $this->returnCallback(function() use ($mockB) {
         return $mockB->fizz($this->bar);
 }));
Run Code Online (Sandbox Code Playgroud)

这在某种程度上是可以实现的吗?

当然没有任何意外,目前,如果我这样做,那么我得到错误:

PHP Fatal error:  Using $this when not in object context in (...)
Run Code Online (Sandbox Code Playgroud)

使用use关键字I可以从父作用域继承$ mockA:

 $mockB = $this->getMock('B');
 // (...) - and probably mock other things
 $mockA = $this->getMock('A', array('foo'));
 $mockA->expects($this->any())->method('foo')->will(
     $this->returnCallback(function() use ($mockA, $mockB) {
         return $mockB->fizz($mockA->bar);
 }));
Run Code Online (Sandbox Code Playgroud)

但这样我会尝试访问公共酒吧,我会得到:

PHP Fatal error:  Cannot access protected property (...)
Run Code Online (Sandbox Code Playgroud)

Fab*_*ler 7

正如其他答案所指出的那样,$this可以在PHP 5.4中使用.一个鲜为人知的事实是,您可以将闭包绑定到任意对象,实际上可以像这样访问它们的私有属性.您需要的方法是bindTo()返回具有不同上下文的新闭包.

$cb = function() {
  return $this->bar;
};
$cb = $cb->bindTo($mockA);
Run Code Online (Sandbox Code Playgroud)

或者更确切地说,您的示例看起来像这样:

 $mockB = $this->getMock('B');
 // (...) - and probably mock other things
 $mockA = $this->getMock('A', array('foo'));
 $fooCallback = function() use (&$mockB) {
     return $mockB->fizz($this->bar);
 };
 $mockA->expects($this->any())->method('foo')->will(
     $this->returnCallback($fooCallback->bindTo($mockA)));
Run Code Online (Sandbox Code Playgroud)


dev*_*ler 0

从 php 5.4 开始,您可以$this在闭包中使用,但您必须从包含这些受保护属性的对象返回此回调:

class A {
    protected $bar = "bar";

    public function foo () {
        $b = new B();
        return $b->fizz($this->bar);
    }

    public function getCallback(B $b) {
        return function() use($b) { 
            return $b->fizz($this->bar);
        };
    }
}

class B {
    public function fizz ($buzz) {
        return $buzz;
    }
}

$mockA = new A;
$mockB = new B;

$callBack = $mockA->getCallback($mockB);
var_dump($callBack() === $mockA->foo());
Run Code Online (Sandbox Code Playgroud)

但是,如果您需要获取受保护属性的值,则应该为其定义公共 getter。这样,测试在 php 5.3 中也可以工作