Web*_*v84 5 php phpunit laravel-5.1
我为我的Laravel 5.1 API构建了一个搜索YouTube的服务.我正在尝试为它编写测试,但我很难弄清楚如何模拟功能.以下是该服务.
class Youtube
{
/**
* Youtube API Key
*
* @var string
*/
protected $apiKey;
/**
* Youtube constructor.
*
* @param $apiKey
*/
public function __construct($apiKey)
{
$this->apiKey = $apiKey;
}
/**
* Perform YouTube video search.
*
* @param $channel
* @param $query
* @return mixed
*/
public function searchYoutube($channel, $query)
{
$url = 'https://www.googleapis.com/youtube/v3/search?order=date' .
'&part=snippet' .
'&channelId=' . urlencode($channel) .
'&type=video' .
'&maxResults=25' .
'&key=' . urlencode($this->apiKey) .
'&q=' . urlencode($query);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result, true);
if ( is_array($result) && count($result) ) {
return $this->extractVideo($result);
}
return $result;
}
/**
* Extract the information we want from the YouTube search resutls.
* @param $params
* @return array
*/
protected function extractVideo($params)
{
/*
// If successful, YouTube search returns a response body with the following structure:
//
//{
// "kind": "youtube#searchListResponse",
// "etag": etag,
// "nextPageToken": string,
// "prevPageToken": string,
// "pageInfo": {
// "totalResults": integer,
// "resultsPerPage": integer
// },
// "items": [
// {
// "kind": "youtube#searchResult",
// "etag": etag,
// "id": {
// "kind": string,
// "videoId": string,
// "channelId": string,
// "playlistId": string
// },
// "snippet": {
// "publishedAt": datetime,
// "channelId": string,
// "title": string,
// "description": string,
// "thumbnails": {
// (key): {
// "url": string,
// "width": unsigned integer,
// "height": unsigned integer
// }
// },
// "channelTitle": string,
// "liveBroadcastContent": string
// }
// ]
//}
*/
$results = [];
$items = $params['items'];
foreach ($items as $item) {
$videoId = $items['id']['videoId'];
$title = $items['snippet']['title'];
$description = $items['snippet']['description'];
$thumbnail = $items['snippet']['thumbnails']['default']['url'];
$results[] = [
'videoId' => $videoId,
'title' => $title,
'description' => $description,
'thumbnail' => $thumbnail
];
}
// Return result from YouTube API
return ['items' => $results];
}
}
Run Code Online (Sandbox Code Playgroud)
我创建了这个服务来从控制器中抽象出功能.然后我用Mockery来测试控制器.现在我需要弄清楚如何测试上面的服务.任何帮助表示赞赏.
需要说的是,由于硬编码curl_*方法,您的类不是为隔离单元测试而设计的。为了让它变得更好,你至少有两个选择:
1)提取curl_*对另一个类的函数调用并将该类作为参数传递
class CurlCaller {
public function call($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
class Youtube
{
public function __construct($apiKey, CurlCaller $caller)
{
$this->apiKey = $apiKey;
$this->caller = $caller;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以轻松模拟 CurlCaller 类。有很多现成的解决方案可以抽象网络。例如,Guzzle就很棒
2) 另一种选择是提取curl_*对受保护方法的调用并模拟该方法。这是一个工作示例:
// Firstly change your class:
class Youtube
{
// ...
public function searchYoutube($channel, $query)
{
$url = 'https://www.googleapis.com/youtube/v3/search?order=date' .
'&part=snippet' .
'&channelId=' . urlencode($channel) .
'&type=video' .
'&maxResults=25' .
'&key=' . urlencode($this->apiKey) .
'&q=' . urlencode($query);
$result = $this->callUrl($url);
$result = json_decode($result, true);
if ( is_array($result) && count($result) ) {
return $this->extractVideo($result);
}
return $result;
}
// This method will be overriden in test.
protected function callUrl($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
Run Code Online (Sandbox Code Playgroud)
现在你可以模拟方法了callUrl。但首先,让我们将预期的 api 响应放入fixtures/youtube-response-stub.json文件中。
class YoutubeTest extends PHPUnit_Framework_TestCase
{
public function testYoutube()
{
$apiKey = 'StubApiKey';
// Here we create instance of Youtube class and tell phpunit that we want to override method 'callUrl'
$youtube = $this->getMockBuilder(Youtube::class)
->setMethods(['callUrl'])
->setConstructorArgs([$apiKey])
->getMock();
// This is what we expect from youtube api but get from file
$fakeResponse = $this->getResponseStub();
// Here we tell phpunit how to override method and our expectations about calling it
$youtube->expects($this->once())
->method('callUrl')
->willReturn($fakeResponse);
// Get results
$list = $youtube->searchYoutube('UCSZ3kvee8aHyGkMtShH6lmw', 'php');
$expected = ['items' => [[
'videoId' => 'video-id-stub',
'title' => 'title-stub',
'description' => 'description-stub',
'thumbnail' => 'https://i.ytimg.com/vi/stub/thimbnail-stub.jpg',
]]];
// Finally assert result with what we expect
$this->assertEquals($expected, $list);
}
public function getResponseStub()
{
$response = file_get_contents(__DIR__ . '/fixtures/youtube-response-stub.json');
return $response;
}
}
Run Code Online (Sandbox Code Playgroud)
运行测试并...天哪,失败了!!1 你的extractVideo方法中有拼写错误,应该是$item而不是$items。让我们修复它
$videoId = $item['id']['videoId'];
$title = $item['snippet']['title'];
$description = $item['snippet']['description'];
$thumbnail = $item['snippet']['thumbnails']['default']['url'];
Run Code Online (Sandbox Code Playgroud)
好吧,现在已经过去了。
如果你想通过调用 Youtube API 来测试你的类,你只需要创建普通的 Youtube 类。
顺便说一句,有php-youtube-api lib,它有 laravel 4 和 laravel 5 的提供程序,也有测试
| 归档时间: |
|
| 查看次数: |
1624 次 |
| 最近记录: |