aeris/ guzzle-http-mock
用于验证使用Guzzle Http客户端发送的请求,并模拟响应的mock库。
Requires
- php: >=5.3.3
- guzzlehttp/guzzle: ~5.0.0
This package is not auto-updated.
Last update: 2024-09-14 16:29:19 UTC
README
用于验证使用Guzzle Http客户端发送的请求,以及模拟响应的mock库。
安装
Composer
您可以使用composer安装GuzzleHttpMock
php composer.phar require --dev aeris/guzzle-http-mock
概述
GuzzleHttpMock允许您设置Http请求期望,并模拟响应。
// Create a guzzle http client $guzzleClient = new \GuzzleHttp\Client([ 'base_url' => 'http://www.example.com' ]); // Create a mock object, and start listening to guzzle client requests $httpMock = new \Aeris\GuzzleHttp\Mock(); $httpMock->attachToClient($guzzleClient); // Setup a request expectation $httpMock ->shouldReceiveRequest() ->withUrl('http://www.example.com/foo') ->withMethod('GET') ->withBodyParams([ 'foo' => 'bar' ]) ->andRespondWithJson([ 'faz', 'baz' ], $statusCode = 200); // Make a matching request $response = $guzzleClient->get('/foo', ['foo' => 'bar']); $response->json() == ['faz' => 'baz']; // true $response->getStatusCode() == 200; // true $httpMock->verify(); // all good. // Make an unexpected request $guzzleClient->post('/bar', ['faz' => 'baz']);; $httpMock->verify(); // UnexpectedHttpRequestException: Request does not match any expectation: // Request url does not match expected value. Actual: '/bar', Expected: '/foo' // Request body params does not match expected value. Actual: [ 'faz' => 'baz'], Expected: ['foo' => 'bar' ]
它是如何工作的?
当GuzzleHttpMock对象附加到Guzzle Http客户端时,它将拦截客户端发出的所有请求。每当发出请求时,mock都会将请求与设置的期望进行比较,并向匹配的请求发送响应。
调用$httpMock->verify()
检查是否已发出所有期望请求,并对任何意外请求提出抗议。
用法
附加到Guzzle客户端
要开始拦截Http请求,GuzzleHttpMock必须附加到GuzzleClient
// Create a guzzle http client $guzzleClient = new \GuzzleHttp\Client([ 'base_url' => 'http://www.example.com' ]); // Create a mock object, and start listening to guzzle client requests $httpMock = new \Aeris\GuzzleHttp\Mock(); $httpMock->attachToClient($guzzleClient);
创建请求期望
shouldReceiveRequest
方法返回一个\Aeris\GuzzleHttpMock\Expectation\RequestExpectation
对象。
$requestExpectation = $httpMock->shouldReceiveRequest();
RequestExpectation
对象使用withXyz
方法设置期望
$requestExpectation->withUrl('http://www.example.com/foo');
期望设置器是可连链的,允许有流畅的接口
$httpMock ->shouldReceiveRequest() ->withUrl('http://www.example.com/foo') ->withMethod('POST');
可用期望
以下期望在\Aeris\GuzzleHttpMock\Expectation\RequestExpectation
对象上可用。
默认期望
默认情况下,期望请求一次,使用Http方法'GET'。
// So this: $httpMock ->shouldReceiveRequest() ->withUrl('http://www.example.com/foo'); // is the same as this: $httpMock ->shouldReceiveRequest() ->withUrl('http://www.example.com/foo') ->once() ->withMethod('GET');
直接设置期望请求
除了单独指定请求期望外,您还可以直接将一个\GuzzleHttp\Message\RequestInterface
对象作为期望设置。
$expectedRequest = $guzzleClient->createRequest([ 'PUT', 'http://www.example.com/foo', [ 'query' => ['faz' => 'baz'], 'body' => json_encode(['shazaam' => 'kablooey']), 'headers' => [ 'Content-Type' => 'application/json' ], ] ]); $httpClient->shouldReceiveRequest($expectedRequest);
自定义期望
所有期望方法都接受一个值或一个callable
作为参数。通过传递一个可调用对象,您可以创建自定义期望。例如
$httpMock ->shouldReceiveRequest() ->withBodyParams(function($actualParams) { return $actualParams['foo'] === 'bar'; });
在这种情况下,如果实际请求体中的foo
参数不等于bar
,则期望将失败。
GuzzleHttpMock还提供了一些内置的自定义期望。例如
use Aeris\GuzzleHttpMock\Expect; $httpMock ->shouldReceiveRequest() // Check URL against a regex ->withUrl(new Expect\Matches('/^https:/')) // Check query params against an array ->withQueryParams(new Expect\ArrayEquals(['foo' => 'bar'])) // Allow any body params ->withBodyParams(new Expect\Any());
模拟响应
当请求与期望匹配时,GuzzleHttpMock将拦截请求,并使用模拟响应进行响应。
$httpMock ->shouldReceiveRequest() ->withMethod('GET') ->withUrl('http://www.example.com/foo') ->andRespondWithJson(['foo' => 'bar']); $response = $guzzleClient->get('/foo'); $response->json() == ['foo' => 'bar']; // true
可用响应
以下方法可用于模拟响应
直接设置模拟响应
您可以使用响应对象直接模拟响应
$response = new \GuzzleHttp\Message\Response( b200, ['Content-Type' = 'application/json'], \GuzzleHttp\Streams\Stream::factory(json_encode(['foo' => 'bar' ]) ); // This is necessary to normalize the response // in a way that Guzzle expects. $messageFactory = \GuzzleHttp\Message\MessageFactory(); $response = $messageFactory->fromMessage($response); $httpMock ->shouldReceiveRequest() ->withMethod('GET') ->withUrl('http://www.example.com/foo') ->andResponseWith($response);
验证期望
可以使用\Aeris\GuzzleHttpMock::verify()
方法验证期望。
$httpMock ->shouldReceiveRequest() ->withUrl('http://www.example.com/foo'); $guzzleClient->get('/bar'); $httpMock->verify(); // UnexpectedRequestException: Request does not match any expectation. // Request url does not match expected value. Actual: '/bar', Expected: '/foo'.
与PHPUnit一起使用
当使用PHPUnit与GuzzleHttpMock一起使用时,请确保将Mock::verify()
添加到您的teardown中
class MyUnitTest extends \PHPUnit_Framework_TestCase { private $guzzleClient; private $httpMock; public function setUp() { // Setup your guzzle client and mock $this->guzzleClient = new \GuzzleHttp\Client([ 'base_url' => 'http://www.example.com' ]); $this->httpMock = new \Aeris\GuzzleHttpMock(); $this->httpMock->attachToClient($this->guzzleClient); } public function tearDown() { // Make sure all request expectations are met. $this->httpMock->verify(); // Failed expectations will throw an \Aeris\GuzzleHttpMock\Exception\UnexpectedHttpRequestException } }
注意事项
我们已经足够内部使用GuzzleHttpMock,感觉可以在生产项目中使用它,但也足够了解还有一些“注意事项”。希望,在事先了解这些问题可以防止许多冲突发生。
如果您想尝试解决这些问题中的任何一个,请查看我们的贡献指南。
未指定期望
在GuzzleHttpMock当前版本中,任何未指定的期望都会导致请求失败。
$httpMock ->shouldReceiveRequest() ->withUrl('http://www.example.com/foo'); $guzzleClient->get('/foo', [ 'query' => ['foo' => 'bar'] ]); $httpMock->verify(); // UnexpectedHttpRequestException: Request does not match any expectation: // Request query params does not match any expectation: Actual: [ 'foo' => 'bar' ], Expected: []
您可能会争辩说,对于未指定的期望,让RequestExpectation默认接受任何值会更有意义。您可能是对的。GuzzleHttpMock的未来版本可能会这样做。
我的UnexpectedRequestException在哪里?
这里有几个可能的罪魁祸首
-
确保您调用了
Mock::verify()
。如果您使用的是测试框架(例如PHPUnit),可以将verify()
放在tearDown
方法中。 -
在您有机会验证请求期望之前,可能已经抛出了另一个异常。
解决第2点可能有些棘手。如果无法匹配RequestExpectation,GuzzleHttpClient将不会响应您的模拟响应,这可能会在您有机会调用verify()
之前导致其他代码出错。
如果您在测试的tearDown
中调用verify()
,您可能想要在http请求之后立即添加另一个verify()
调用。
您还可以尝试将导致问题的代码包裹在try...catch
块中,以便为UnexpectedRequestException
提供优先级。
$this->httpMock ->shouldReceiveRequest() ->withXYZ() ->andRespondWith($aValidResponse); try { $subjectUnderTest->doSomethingWhichExpectsAValidHttpResponse(); } catch (\Exception $ex) { // uh oh, $subjectUnderTest made an unexpected request, // and now if does not have a valid response to work with! // Let's check our http mock, and see what happened $httpMock->verify(); // If it's not a request expectation problem, throw the original error $throw ex; }
这可能比您在所有测试中都希望看到的更详细,但如果您在调试时,这可能会很有帮助。
为什么它会做我不认为它应该做的事情?
我不知道。这真的很奇怪。太遗憾了...
嘿,为什么不开一个新的问题,并告诉我们?也许我们可以帮忙。
贡献
为了那种温暖舒适的开源感觉,今天为GuzzleHttpMock做出贡献吧!
我们只要求您包含PHPUnit测试,并在需要时更新文档。另外,如果您的问题不是开放问题或不在我们的愿望清单上,您可能首先想开一个问题,以确保您走的方向是正确的。
愿望清单
请查看“注意事项”部分,了解一些可以修复的问题。还有其他想法?开一个问题,我们会讨论的。