【发布时间】:2017-10-19 09:54:54
【问题描述】:
以下是我的phpspec代码
function it_throws_if_raw_data_xml_is_invalid()
{
$website = $this->buildWebsite("some-deterministic-id", "some-deterministic-name");
$this->convertAdwordsRawData($website, "yesterday", "invalidXML");
$this->shouldThrow(AdwordsResponseNotParseable::class)
->during("convertAdwordsRawData", [$website, "yesterday", "invalid-xml"]);
}
测试失败,但不是因为逻辑错误,而是因为convertAdwordsRawData 永远不会被调用。我在其中添加了 var_dump 并且它没有显示出来,而构造函数的输出通过了。我尝试传递字符串而不是 $website,但遇到了类型提示问题。如果我只是在没有断言的情况下调用测试内部的方法,它永远不会调用该方法并通过测试,而不从 var_dump 输出任何内容。总而言之,phpspec 只是不为我执行该方法。它上面的一个测试,测试相同的公共方法,工作得很好。
这里可能有什么问题?
为了论证起见,考虑该方法执行以下操作
public function convertAdwordsRawData(Websites $website, string $time, string $rawData): \Generator
{
var_dump("Here I am");
throw new AdwordsResponseNotParseable($rawData);
yield from [1,2,3,4,5];
}
更新 好的,这一切都归结为 php 如何处理生成器。方法调用将返回一个尚未初始化的迭代器。当我在实际返回的生成器上调用该方法时,PHP 将运行所有内容,直到第一次迭代的第一次产量,并在任何连续的迭代中返回产量。
来自 php.net 网站
当一个生成器函数第一次被调用时,一个对象 返回内部生成器类。这个对象实现了 迭代器接口
$this->convertAdwordsRawData(...)->shouldThrow(...)->duringCurrent();
是解决方案。 current() 调用来自于 PHP 中 Iterator 的实现——每次迭代都会调用这个方法
【问题讨论】:
-
不看就很难发现函数内部出了什么问题。但是尝试在 xdebug 中设置断点,然后单步执行以找出问题所在。 XDebug 是一款非常快速、强大且有用的工具,可用于调试此类错误。
-
感谢您的回复。问题不在于函数,问题在于 phpspec 本身。该方法根本不会被调用。我可以使用 xDebug 遍历 phpspec 的内部结构,但老实说我希望它不会出现这种情况