2015-11-05 79 views
2

我正在開發一個symfony 2項目。我有一個類,這取決於輸入值創建一個URL並啓動一個請求到外部系統。處理響應並返回處理結果。symfony:如何根據請求的URL來模擬對Guzzle Api請求的響應

對於這個類,功能測試正在工作。在這種情況下,這意味着我正在運行測試,這確實會調用外部服務並處理真正的答案。 現在我想添加真正的單元測試,所以我必須嘲笑我的請求和結果。對於我使用Guzzle Http Client的請求。 我想實現的是,如果我的方法調用url「http://example.com/certain/parameters」,那麼我只希望答案是「baa」。通過這個,我想測試請求url是否正確構建,並且生成的響應是否正確處理。

但是,我完全卡住如何做嘲笑。

該測試運行一個公用方法,該方法調用私有方法。這裏是我的類的私有方法,它包含了狂飲的一部分:

/** 
* 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在$客戶端的‘獲取’方法設置。然後用於獲取響應的「send」方法,這是send方法返回的對象。 我想要將get調用的輸入值與發送調用的結果連接起來。

我嘗試了很多,但到目前爲止沒有真正的工作。

一個非工作的例子是:

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致命錯誤:在空

調用一個成員函數getPreviewUrl()任何一個有提示如何實現這一目標?它甚至有可能嗎?

+0

一個選項可能是將URL的組裝和處理分離爲兩種公共方法。但是因爲公開的唯一理由是分離的可測試性,所以我很猶豫要這樣做。 –

回答

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); 
} 

在測試方法中,我T稱爲象如下:

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方法。

通過這個模擬行爲就像它應該:它只會返回所需的值,如果匹配的值被我的測試類使用。