在某些情况下,我们需要调用第三方提供的HTTP API来获取特定的信息。在Laravel中,我们可以使用curl来调用HTTP API。在开发和测试的过程中,我们不可以调用真实的API,真实的API可能是需要付费的,所以我们需要Mock API的调用。
在本文中,虽然讲的是如何Mock curl,但是也可以推广到如何Mock PHP的标准方法。下面是一个简单的例子,我将针对这个例子进行mock测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class CurlService { public function getContentFrom($url) { $curl = curl_init(); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Accept: application/json', 'Content-Type: application/json' ]); $response = curl_exec($curl); return json_decode($response); } }
|
使用第三方包
php-mock/php-mock-phpunit
是一个第三包,它对PHPUnit进行了扩展,让我们能够更加轻松地对一个方法进行Mock。
使用下面的命令安装:
composer require --dev php-mock/php-mock-phpunit
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public function testShouldReturnResponseWhenCallGetContentFromGivenURL() { $url = 'https://generator.swagger.io/api/gen/clients/android'; $response = ['status' => 200, 'data' => ['id' => 1]]; $curl = $this->getFunctionMock('App\Service', 'curl_exec'); $curl->expects($this->any())->willReturn(json_encode($response));
$service = new CurlService(); $result = $service->getContentFrom($url);
self::assertEquals($response['status'], $result->status); self::assertEquals($response['data']['id'], $result->data->id); }
|
$this->getFunctionMock('App\Service', 'curl_exec')
中App\Service
是指curl_exec
所在的namespace,如果你是在 App\Controller
中调用该方法,则该处就应该是 App\Controller
。
重载内置函数
重载namespace下的 curl_exec
,如下代码所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| namespace App\Service {
function curl_exec() { return json_encode(['status' => 200, 'data' => ['id' => 1]]); } }
namespace Tests\Service {
use App\Service\CurlService; use PHPUnit\Framework\TestCase;
class CurlServiceTest extends TestCase { public function testShouldReturnResponseWhenCallGetContentFromGivenURL() { $url = 'https://generator.swagger.io/api/gen/clients/android'; $response = ['status' => 200, 'data' => ['id' => 1]];
$service = new CurlService(); $result = $service->getContentFrom($url);
self::assertEquals($response['status'], $result->status); self::assertEquals($response['data']['id'], $result->data->id); }
} }
|
使用类封装
将 curl
这样PHP inbuilt函数封装到一个新的类中,我们就可以通过Mock这个新的类进而mock inbuilt函数。
代码如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| class Curl { private $curl;
public function __construct() { $this->curl = curl_init(); }
public function setopt($key, $value) { curl_setopt($this->curl, $key, $value); }
public function exec() { return curl_exec($this->curl); } }
class CurlService { private $curl;
public function __construct($curl) { $this->curl = $curl; }
public function getContentFrom($url) { $this->curl->setopt(CURLOPT_RETURNTRANSFER, 1); $this->curl->setopt(CURLOPT_URL, $url); $this->curl->setopt(CURLOPT_HTTPHEADER, [ 'Accept: application/json', 'Content-Type: application/json' ]); $response = $this->curl->exec(); return json_decode($response); } }
class CurlServiceTest extends TestCase { public function testShouldReturnWhenCallGetContentFromGivenURL() { $url = 'https://generator.swagger.io/api/gen/clients/android'; $response = ['status' => 200, 'data' => ['id' => 1]]; $curlMock = \Mockery::mock(Curl::class); $curlMock->shouldReceive('setopt'); $curlMock->shouldReceive('exec')->andReturn(json_encode($response));
$service = new CurlService($curlMock); $result = $service->getContentFrom($url);
self::assertEquals($response['status'], $result->status); self::assertEquals($response['data']['id'], $result->data->id); }
}
|