2013-02-09 27 views
7

可以使用$這裏面回調以獲取PHPUnit中嘲笑類的保護性能? 或者有其他方法可以實現嗎?

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

這可能是非常有用的,如果你考慮注入模擬對象。 有時類有其他類的硬編碼的依賴,但它與方法,理論上你可以嘲笑和戲弄創建對象,而不是硬編碼的對象創建它。請看另一個例子。

class A { 
    protected $bar = "bar"; 

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

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

但讓我們說B類做的不好,我想用模擬來代替它。

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

這是否可以實現?

當然沒有任何驚喜,目前,如果我這樣做像上面然後我得到錯誤:

PHP Fatal error: Using $this when not in object context in (...) 

使用use關鍵字我可以從父作用域繼承$ 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); 
})); 

但這樣我會嘗試訪問酒吧作爲公衆,我會得到:

PHP Fatal error: Cannot access protected property (...) 

回答

0

S因斯的是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()); 

但是,如果你需要得到保護的屬性值,你應該定義公共的getter爲了它。通過這種方式,測試也將在PHP 5.3

+0

是的,我知道我可以定義公共的getter但可以說這是一個外部庫,或者你只是想保持它的保護。整個問題是關於如何在特定情況下獲得類的受保護屬性。所以對於PHP 5.3來說,答案仍然是否定的,你不能那樣做。對於PHP 5.4,你可以使用$ this!這是一個巨大的進步!但仍然需要改變我不想改變的課程。你至少可以創建擴展A的類來添加'getCallback(B $ b)'?需要檢查。 – 2013-02-10 12:59:52

1

工作作爲dev所無效居民指出,在PHP 5.4,你可以關閉中使用$此,如果你在那裏的法正常工作。

在5.3,你可以通過做模仿這種行爲:

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

至於其他的答案已經指出,$this可以在閉包,因爲PHP 5.4中使用。一個鮮爲人知的事實是,你可以將一個閉包綁定到任意對象,並且實際上可以像這樣訪問它們的私有屬性。你需要的方法是bindTo(),它返回一個新的閉包有不同的上下文。

$cb = function() { 
    return $this->bar; 
}; 
$cb = $cb->bindTo($mockA); 

或者更準確地說,你的例子看起來像:

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

提及此功能的+1。 PHPUnit也鼓勵使用PHP 5。4,所以這可能是開始製作開關的好時機。 (也請注意自我:) :)) – qrazi 2013-02-11 12:31:25