当我自己尝试使用 cURL 测试一个类时,我偶然发现了这个问题。我将 David Harkness 的建议铭记于心,并为 cURL 创建了一个界面。但是,PHPUnit 提供的 stub/mock 功能在我的情况下是不够的,所以我添加了自己的接口实现,并将其全部放在 GitHub 上。而且因为这个问题在谷歌搜索这个问题时很早就出现了,所以我想我会在这里发布它,这样其他人也许可以节省工作量。
Here it is.
repository's wiki 包含有关存根功能的相当详细的文档,但在这里它们很简短。
接口是PHP的cURL函数的1:1映射,这样可以很容易上手使用接口(只需将你的ClassUnderTest交给一个实现SAI_CurlInterface的实例,然后像以前一样调用所有cURL函数,但作为该实例的方法)。 SAI_Curl 类通过简单地委托给 cURL 来实现这个接口。现在如果你想测试ClassUnderTest,你可以给它一个SAI_CurlStub的实例。
stub 主要缓解 PHPUnit 的 mocks 和 stubs 不能根据以前的函数调用返回虚拟数据的问题(但这就是 cURL 的实际工作方式 - 你设置你的选项,响应、错误代码和 cURL 信息取决于那些选项)。因此,这里有一个简短的示例,展示了响应的这些功能(有关错误代码和 cURL 信息,请参阅 wiki)。
public function testGetData()
{
$curl = new SAI_CurlStub();
// Set up the CurlStub
$defaultOptions = array(
CURLOPT_URL => 'http://www.myserver.com'
);
$chromeOptions = array(
CURLOPT_URL => 'http://www.myserver.com',
CURLOPT_USERAGENT => 'Chrome/22.0.1207.1'
);
$safariOptions = array(
CURLOPT_URL => 'http://www.myserver.com',
CURLOPT_USERAGENT => 'Safari/537.1'
);
$curl->setResponse('fallback response');
$curl->setResponse('default response from myserver.com'
$defaultOptions);
$curl->setResponse('response for Chrome from myserver.com',
$chromeOptions);
$curl->setResponse('response for Safari from myserver.com',
$safariOptions);
$cut = new ClassUnderTest($curl);
// Insert assertions to check whether $cut handles the
// different responses correctly
...
}
您可以根据任何 cURL 选项的任意组合做出响应。当然,你可以更进一步。例如,您的ClassUnderTest 从服务器获取一些 XML 数据并对其进行解析(好吧,您应该为这些任务有两个单独的类,但我们假设我们的示例是这样的),并且您想要测试该行为。您可以手动下载 XML 响应,并让您的测试从文件中读取数据并将其填充到响应中。然后你就可以确切地知道那里有什么数据,并且可以检查它是否被正确解析。或者,您可以实现 SAI_CurlInterface 立即从您的文件系统加载所有响应,但现有的实现绝对是一个起点。
在我写这个答案的时候,@SAI_CurlStub@ 还不支持 cURL 多库功能,但我也计划在未来实现这一点。
我希望这个存根对任何想要对依赖于 cURL 的类进行单元测试的人有所帮助。随意查看和使用这些课程,或者做出贡献,当然——毕竟它在 GitHub 上:)。此外,我愿意接受任何关于接口和存根的实现和使用的建设性批评。