2pd / guzzle-http-mock
用于验证使用Guzzle Http客户端发出的请求并模拟响应的模拟库。
This package is not auto-updated.
Last update: 2024-09-19 13:08:46 UTC
README
用于验证使用Guzzle Http客户端发出的请求并模拟响应的模拟库。
这是原始版本的分支。这个版本被修改以支持Guzzle 6,并做了一些其他的小改动。
安装
Composer
您可以使用Composer安装GuzzleHttpMock
php composer.phar require --dev systemhaus/guzzle-http-mock
概述
GuzzleHttpMock允许您设置HTTP请求期望并模拟响应。
// Create a mock object $httpMock = new \Aeris\GuzzleHttp\Mock(); // Create a guzzle http client and attach the mock handler $guzzleClient = new \GuzzleHttp\Client([ 'base_url' => 'http://www.example.com', 'handler' => $httpMock->getHandlerStackWithMiddleware(); ]); // 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', ['json' => ['foo' => 'bar'] ]); json_decode((string) $response->getBody(), true) == ['faz' => 'baz']; // true $response->getStatusCode() == 200; // true $httpMock->verify(); // all good. // Make an unexpected request $guzzleClient->post('/bar', ['json' => ['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客户端时,它将截获客户端发出的所有请求。每当发出请求时,模拟会检查请求是否符合设置的期望,并向匹配的请求发送响应。如果您的客户端使用自定义中间件,您可以将其附加到模拟处理器的处理器堆栈中。
调用$httpMock->verify()
将检查所有预期的请求是否都已发出,并对任何意外的请求提出抱怨。
使用方法
附加到Guzzle客户端
要开始截获HTTP请求,GuzzleHttpMock必须附加到GuzzleClient
// Create a mock object $httpMock = new \Aeris\GuzzleHttp\Mock(); // Create a guzzle http client and attach mock handler $guzzleClient = new \GuzzleHttp\Client([ 'base_url' => 'http://www.example.com', 'handler' => $httpMock->getHandlerStackWithMiddleware() ]);
创建请求期望
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');
直接设置期望请求
除了单独指定请求期望外,您还可以直接将Psr\Http\Message\RequestInterface
对象设置为期望。
$expectedRequest = new Request( 'PUT', 'http://www.example.com/foo?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'; });
在这种情况下,如果实际请求体中有不等于bar
的foo
参数,则期望将失败。
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\Psr7\Response( 200, ['Content-Type' = 'application/json'], json_encode(['foo' => 'bar' ] ); $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一起使用
在使用 GuzzleHttpMock 与 PHPUnit 结合时,请确保在 teardown 中添加 Mock::verify()
。
class MyUnitTest extends \PHPUnit_Framework_TestCase { private $guzzleClient; private $httpMock; public function setUp() { // Setup your guzzle client and mock $this->httpMock = new \Aeris\GuzzleHttpMock(); $this->guzzleClient = new \GuzzleHttp\Client([ 'base_url' => 'http://www.example.com', 'handler' => $this->httpMock->getHandlerStackWithMiddleware(); ]); } 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),你可以在tearDown
方法中添加verify()
。 -
在你有机会验证你的请求期望之前,可能已经抛出了另一个异常。
解决第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 测试,并根据需要更新文档。此外,如果不是开放性问题或在我们的愿望清单上,你可能首先想要打开一个问题,以确保你的方向是正确的。
愿望列表
查看“陷阱”部分,了解一些可以解决的问题。有其他想法吗?打开一个问题,我们会讨论。