From a36797d60eef1c108835059c9a6dc7675fdbfa08 Mon Sep 17 00:00:00 2001 From: Konstantin Myakshin Date: Sat, 7 Dec 2019 04:42:36 +0200 Subject: [PATCH] Allow pass array of callable to the mocking http client --- .../Component/HttpClient/MockHttpClient.php | 12 +- .../HttpClient/Tests/MockHttpClientTest.php | 121 ++++++++++++++++++ 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpClient/MockHttpClient.php b/src/Symfony/Component/HttpClient/MockHttpClient.php index cb3cb969b0..d69276ffb2 100644 --- a/src/Symfony/Component/HttpClient/MockHttpClient.php +++ b/src/Symfony/Component/HttpClient/MockHttpClient.php @@ -29,9 +29,10 @@ class MockHttpClient implements HttpClientInterface private $responseFactory; private $baseUri; + private $requestsCount = 0; /** - * @param callable|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory + * @param callable|callable[]|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory */ public function __construct($responseFactory = null, string $baseUri = null) { @@ -64,9 +65,11 @@ class MockHttpClient implements HttpClientInterface } elseif (!$this->responseFactory->valid()) { throw new TransportException('The response factory iterator passed to MockHttpClient is empty.'); } else { - $response = $this->responseFactory->current(); + $responseFactory = $this->responseFactory->current(); + $response = \is_callable($responseFactory) ? $responseFactory($method, $url, $options) : $responseFactory; $this->responseFactory->next(); } + ++$this->requestsCount; return MockResponse::fromRequest($method, $url, $options, $response); } @@ -84,4 +87,9 @@ class MockHttpClient implements HttpClientInterface return new ResponseStream(MockResponse::stream($responses, $timeout)); } + + public function getRequestsCount(): int + { + return $this->requestsCount; + } } diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index bce4bfafea..d21e3f50a9 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -22,6 +22,127 @@ use Symfony\Contracts\HttpClient\ResponseInterface; class MockHttpClientTest extends HttpClientTestCase { + /** + * @dataProvider mockingProvider + */ + public function testMocking($factory, array $expectedResponses) + { + $client = new MockHttpClient($factory, 'https://example.com/'); + $this->assertSame(0, $client->getRequestsCount()); + + $urls = ['/foo', '/bar']; + foreach ($urls as $i => $url) { + $response = $client->request('POST', $url, ['body' => 'payload']); + $this->assertEquals($expectedResponses[$i], $response->getContent()); + } + + $this->assertSame(2, $client->getRequestsCount()); + } + + public function mockingProvider(): iterable + { + yield 'callable' => [ + static function (string $method, string $url, array $options = []) { + return new MockResponse($method.': '.$url.' (body='.$options['body'].')'); + }, + [ + 'POST: https://example.com/foo (body=payload)', + 'POST: https://example.com/bar (body=payload)', + ], + ]; + + yield 'array of callable' => [ + [ + static function (string $method, string $url, array $options = []) { + return new MockResponse($method.': '.$url.' (body='.$options['body'].') [1]'); + }, + static function (string $method, string $url, array $options = []) { + return new MockResponse($method.': '.$url.' (body='.$options['body'].') [2]'); + }, + ], + [ + 'POST: https://example.com/foo (body=payload) [1]', + 'POST: https://example.com/bar (body=payload) [2]', + ], + ]; + + yield 'array of response objects' => [ + [ + new MockResponse('static response [1]'), + new MockResponse('static response [2]'), + ], + [ + 'static response [1]', + 'static response [2]', + ], + ]; + + yield 'iterator' => [ + new \ArrayIterator( + [ + new MockResponse('static response [1]'), + new MockResponse('static response [2]'), + ] + ), + [ + 'static response [1]', + 'static response [2]', + ], + ]; + + yield 'null' => [ + null, + [ + '', + '', + ], + ]; + } + + /** + * @dataProvider transportExceptionProvider + */ + public function testTransportExceptionThrowsIfPerformedMoreRequestsThanConfigured($factory) + { + $client = new MockHttpClient($factory, 'https://example.com/'); + + $client->request('POST', '/foo'); + $client->request('POST', '/foo'); + + $this->expectException(TransportException::class); + $client->request('POST', '/foo'); + } + + public function transportExceptionProvider(): iterable + { + yield 'array of callable' => [ + [ + static function (string $method, string $url, array $options = []) { + return new MockResponse(); + }, + static function (string $method, string $url, array $options = []) { + return new MockResponse(); + }, + ], + ]; + + yield 'array of response objects' => [ + [ + new MockResponse(), + new MockResponse(), + ], + ]; + + yield 'iterator' => [ + new \ArrayIterator( + [ + new MockResponse(), + new MockResponse(), + ] + ), + ]; + } + protected function getHttpClient(string $testCase): HttpClientInterface { $responses = [];