我正在单元测试一个URL提取器,我需要一个总是导致urllib2.urlopen()
(Python)超时的测试URL。我尝试过制作一个php页面,其中只有sleep(10000),但这会导致500内部服务器错误。
当请求时,我将如何在客户端中创建导致连接超时的资源?
编辑:我看到了[php]标记,并认为这是php代码--然而,如果您使用的是Python语言,那么同样的原则也可以应用于Python。
成功的单元测试要求您在与所有外部影响完全隔离的情况下测试代码单元。这意味着,如果您的测试依赖于文件系统(或者在本例中是某个外部web服务器)之类的东西才能正常运行,那么您就做错了。当你的测试依赖于外部网络服务器时,你会给测试代码增加很大的复杂性,并引入假阳性和其他错误测试结果的可能性。
听起来,当前的测试实现需要一个全面的模拟web服务器来提供特定的、可测试的响应情况不应该如此。这种影响深远的测试依赖性只会导致上述问题。
更好的方式
但是,如何测试原生PHP功能及其与远程数据(如HTTP或FTP)的交互?答案是将test"seams">添加到代码中。考虑以下简单示例:
<?php
class UrlRetriever {
public function retrieve($uri) {
$response = $this->doRetrieve($uri);
if (false !== $response) {
return $response;
} else {
throw new RuntimeException(
'Retrieval failed for ' . $uri
);
}
}
/**
* A test seam to allow mocking of `file_get_contents` results
*/
protected function doRetrieve($uri) {
// suppress the warning from a failure since we're testing against the
// return value (FALSE on failure)
return @file_get_contents($uri);
}
}
你的相关PHPUnit测试看起来像这样:
<?php
class UrlRetrieverTest extends PHPUnit_Framework_TestCase {
/**
* @covers UrlRetriever::retrieve
* @expectedException RuntimeException
*/
public function testRetrieveThrowsExceptionOnFailure() {
$retriever = $this->getMock('UrlRetriever', array('doRetrieve'));
$retriever->expects($this->once())
->method('doRetrieve')
->will($this->returnValue(false));
$retriever->retrieve('http://someurl');
}
/**
* @covers UrlRetriever::retrieve
*/
public function testSomeSpecificOutputIsHandledCorrectly() {
$expectedValue = 'Some value I want to manipulate';
$retriever = $this->getMock('UrlRetriever', array('doRetrieve'));
$retriever->expects($this->once())
->method('doRetrieve')
->will($this->returnValue($expectedValue));
$response = $retriever->retrieve('http://someurl');
$this->assertEquals($response, $expectedValue);
}
}
显然,这个例子是人为设计的,非常简单,但这个概念可以根据需要扩展。通过创建像上面的UrlRetriever::doRetrieve
方法这样的测试接缝,我们可以使用标准测试框架轻松地模拟结果。
这种方法使我们能够测试本机PHP函数的复杂结果,这些函数操作远程资源,而无需接触外部web服务器,也无需在测试系统之外引入错误的可能性。
在OP的特定情况下,如果需要超时结果,只需模拟相关的测试接缝方法,以执行本地PHP函数在超时时会执行的任何操作。
您尝试过httpbin的/delay
吗?
httpbin是一个HTTP请求&响应服务用Python编写(我认为Kenneth Reitz开发它是为了在编写requests
模块时测试它),源代码在GitHub上。实际上,我不确定/delay
是否会延迟接受请求连接或发送响应。但如果它不完全符合您的需求,那么修改或扩展它应该非常容易
连接超时?例如,使用netcat
。监听某个端口(nc -l
),然后尝试从该端口下载数据。.http://localhost:port/
。它将打开连接,但永远不会回复。
在PHP中,您可以发送状态代码为408 的标头
header("HTTP/1.0 408 Request Timeout");
虽然这里有一些不错的答案,但我发现我只需要一个简单的php sleep()调用,并覆盖Apache的超时。
我知道单元测试应该是孤立的,但这个端点所在的服务器是不会有任何进展的。