我试图找到一种方法来检查传递给我的单元测试中的方法的Closure函数是否已被调用一次。但是PHP中的Closure类被声明为final,当我运行它时会收到以下错误消息:" Class" Closure"宣布"最终"并且不能被嘲笑。"
这是一个代码示例。我试图检查valueProducer()是否已被调用一次。
class PoorCache{
protected $storage;
/**
* Returns value from cache and if the value lacks puts it into the cache storage
* @param string $key
* @param Closure $valueProducer produces a value for storage, i.e. makes a request to DB
* @return mixed
*/
public function remember($key, Closure $valueProducer)
{
if (array_key_exists($key, $this->storage))
{
return $this->storage[$key];
}
$this->storage[$key] = $valueProducer();
return $this->storage[$key];
}
}
class PoorCacheTest extends TestCase {
public function testRemeber(){
$mockedValueProducer = $this->getMock(\Closure::class);
$mockedValueProducer->expects($this->once())->method('call');
$cache = new PoorCache();
$cache->remember('myKey', $mockedValueProducer);
$cache->remember('myKey', $mockedValueProducer);
}
}
答案 0 :(得分:1)
您可以创建一个不存在的双精度类,并将其实现__invoke
方法。但是double不会是\Closure
的实例,因此您必须删除\Closure
方法的remember
类型提示。
// Create double
$double = $this->getMockBuilder('NonExistentClass')
->setMethods(['__invoke'])
->getMock();
// Set expectations
$double->expects($this->once())->method('__invoke');
// Test
$double();
答案 1 :(得分:0)
不是存储给定闭包的结果,而是存储闭包,然后调用一次。
像这样:
class PoorCache {
protected $storage;
private $called = [];
/**
* Returns value from cache and if the value lacks puts it into the cache storage
* @param string $key
* @param Closure $valueProducer produces a value for storage, i.e. makes a request to DB
* @return null
*/
public function remember($key, Closure $valueProducer)
{
// store $valueProducder Closure
$this->storage[$key] = $valueProducer;
if(isset($this->called[$key])) {
unset($this->called[$key]);
}
return null;
}
// call producer closure by key
public function callProducer($key)
{
if(isset($this->storage[$key])) {
// check if $key has been called
// if true returns false
if(isset($this->called[$key])) {
return false;
}
// add $key to called array
$this->called[] = $key;
// call closure
return ($this->storage[$key])();
}
}
}
class PoorCacheTest extends TestCase {
public function testRemeber(){
$mockedValueProducer = $this->getMock(\Closure::class);
$mockedValueProducer->expects($this->once())->method('call');
$cache = new PoorCache();
// store closure once
$cache->remember('myKey', $mockedValueProducer);
// store closure twice
// this is going to override the own before it
// since they both have the same key
$cache->remember('myKey', $mockedValueProducer);
// call producer once
$cache->callProducer('myKey');
// call producer twice
// NOTE: this going to return false since 'myKey'
// has already been called
$cache->callProducer('myKey');
}
}