我正在研究一个symfony 2项目。我有一个类,它根据输入值创建一个URL并启动对外部系统的请求。处理响应并返回处理结果。
对于本课程,功能测试正在进行中。在这种情况下,这意味着我正在运行测试,它真正调用外部服务并处理真正的答案。 现在我想添加真正的单元测试,所以我必须模拟我的请求和结果。对于我使用Guzzle Http客户端的请求。 我想要实现的是,如果我的方法只是调用url“http://example.com/certain/parameters”,那么我希望答案是“baa”。通过这个我想测试请求URL是否正确构建,并正确处理结果响应。
然而,我完全陷入了如何进行嘲弄的困境。
测试运行一个调用私有方法的公共方法。这是我的类'私有方法的一部分,其中包含Guzzle:
/**
* Fetch the Preview Urls from Cache Server.
*
* @param string $sCacheUrl
* @param integer $iObjnbr
*
* @return mixed
*/
private function fetchPreviewUrls($sCacheUrl, $iObjnbr)
{
$this->client = $this->client->get($sCacheUrl);
$response = $this->client->send();
if ($response->getStatusCode() <> 200) {
$this->logger->error('Image cache server unreachable. Http status "' . $response->getStatusCode() . '"');
} else {
$this->logger->debug('new cache url is "' . $response->getBody(true) . '"');
}
$json = $response->getBody(true);
//echo $json;
$aPreviews = $this->processJson($json, $iObjnbr);
//var_dump($aPreviews);
$aTeaser = array_shift($aPreviews);
if (empty($aTeaser)) {
$aTeaser = $aPreviews;
}
//var_dump($aTeaser);
return $aTeaser['url'];
}
棘手的部分是url是在$ client的“get”方法中设置的。然后用“send”方法获取响应,这是send方法返回的对象。 我想将get调用的输入值与send调用的结果相连接。
我尝试了很多,但到目前为止还没有真正奏效。
其中一个非工作的例子是:
public function testGetPreviewUrlBigImage()
{
$this->mockLogger = $this->getMock('\Psr\Log\LoggerInterface');
// given
$url = 'http://i5.example.com/teaser.php?action=list&objnbr=60963198&size=320';
$json =
'{"60963198":{"0":{"url":"http:\/\/i1.example.com\/teaser\/320\/8\/60963198.jpeg","size":320,"type":""}}}';
$clientMethods = get_class_methods('\Guzzle\Http\Client');
$this->mockClient = $this->getMock('\Guzzle\Http\Client', $clientMethods);
$this->mockClient->expects($this->any())->method('get')->method('send')->will(
$this->returnCallback(
function ($argument) use ($json, $url) {
$response = new \Guzzle\Http\Message\Response(200, [], $json);
return ($argument == $url) ? $response : false;
}
)
);
$this->linkService = new DefaultPreviewImageLinkService($this->mockLogger, $this->mockClient);
// when
$previewUrl = $this->linkService->getPreviewUrl(60963198, '', DefaultPreviewImageLinkService::IMAGE_BIG);
// then
$this->assertStringEndsWith('.jpeg', $previewUrl);
$this->assertRegExp('/^http:\/\/i[0-9]{1}.*/', $previewUrl);
$this->assertRegExp('/.*320.*jpeg/', $previewUrl);
}
导致致命错误 PHP致命错误:在null
上调用成员函数getPreviewUrl()任何人都有提示如何实现这一目标?它甚至可能吗?
答案 0 :(得分:1)
在francisco-spaeth的帮助下,我解决了这个问题:
我们就是这样做的:
在测试类中添加了三个私有属性:
private $mockLogger;
private $mockClient;
private $linkService;
我添加了一种准备模拟的方法
public function prepareMocks($url, $json)
{
$responseInterface = $this->getMockBuilder('\Guzzle\Http\Message\Response')
->disableOriginalConstructor()
->getMock();
$responseInterface->method('getBody')
->with($this->equalTo(true))
->will($this->returnValue($json));
$requestInterface = $this->getMock('\Guzzle\Http\Message\RequestInterface');
$requestInterface->method('send')->will($this->returnValue($responseInterface));
$this->mockClient = $this->getMock('\Guzzle\Http\Client');
$this->mockClient->method('get')
->with($this->equalTo($url))
->will($this->returnValue($requestInterface));
$this->linkService = new DefaultPreviewImageLinkService($this->mockLogger, $this->mockClient);
}
在测试方法中,它被称为如下:
public function testGetPreviewUrlBigImage()
{
// Given:
$url = 'http://i1.example.com/teaser.php?action=list&objnbr=60963198&size=320';
$json = '{"60963198":{"0":{"url":"http:\/\/i1.example.com\/teaser\/320\/8\/60963198.jpeg",'
. '"size":320,"type":""}}}';
$this->prepareMocks($url, $json);
$class_methods = get_class_methods($this->linkService);
// When:
$previewUrl = $this->linkService->getPreviewUrl(60963198, '', DefaultPreviewImageLinkService::IMAGE_BIG);
// Then:
$this->assert.....
}
通过在方法中准备模拟,我保持代码清洁,因为必须为每个测试调用它。 我只是将所需的输入值提供给prepareMock方法。
通过这种方式,模拟的行为应该如下:如果我的测试类使用了匹配的值,它只会返回所需的值。