8000 Merge branch '4.4' into 5.3 · symfony/symfony-docs@458cb01 · GitHub
[go: up one dir, main page]

Skip to content

Commit 458cb01

Browse files
committed
Merge branch '4.4' into 5.3
* 4.4: Minor tweaks [HttpClient] More on testing, how to test request, example
2 parents 2971bd8 + 6da4548 commit 458cb01

File tree

1 file changed

+133
-5
lines changed

1 file changed

+133
-5
lines changed

http_client.rst

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,7 +1279,7 @@ Symfony's HTTP client provides an EventSource implementation to consume these
12791279
server-sent events. Use the :class:`Symfony\\Component\\HttpClient\\EventSourceHttpClient`
12801280
to wrap your HTTP client, open a connection to a server that responds with a
12811281
``text/event-stream`` content type and consume the stream as follows::
1282-
1282+
12831283
use Symfony\Component\HttpClient\Chunk\ServerSentEvent;
12841284
use Symfony\Component\HttpClient\EventSourceHttpClient;
12851285

@@ -1627,12 +1627,27 @@ has many safety checks that will throw a ``LogicException`` if the chunk
16271627
passthru doesn't behave correctly; e.g. if a chunk is yielded after an ``isLast()``
16281628
one, or if a content chunk is yielded before an ``isFirst()`` one, etc.
16291629

1630-
Testing HTTP Clients and Responses
1631-
----------------------------------
1630+
Testing
1631+
-------
16321632

16331633
This component includes the ``MockHttpClient`` and ``MockResponse`` classes to
1634-
use them in tests that need an HTTP client which doesn't make actual HTTP
1635-
requests.
1634+
use in tests that shouldn't make actual HTTP requests. Such tests can be
1635+
useful, as they will run faster and produce consistent results, since they're
1636+
not dependent on an external service. By not making actual HTTP requests there
1637+
is no need to worry about the service being online or the request changing
1638+
state, for example deleting a resource.
1639+
1640+
``MockHttpClient`` implements the ``HttpClientInterface``, just like any actual
1641+
HTTP client in this component. When you type-hint with ``HttpClientInterface``
1642+
your code will accept the real client outside tests, while replacing it with
1643+
``MockHttpClient`` in the test.
1644+
1645+
When the ``request`` method is used on ``MockHttpClient``, it will respond with
1646+
the supplied ``MockResponse``. There are a few ways to use it, as described
1647+
below.
1648+
1649+
HTTP Client and Responses
1650+
~~~~~~~~~~~~~~~~~~~~~~~~~
16361651

16371652
The first way of using ``MockHttpClient`` is to pass a list of responses to its
16381653
constructor. These will be yielded in order when requests are made::
@@ -1769,6 +1784,119 @@ Then configure Symfony to use your callback:
17691784
;
17701785
};
17711786
1787+
Testing Request Data
1788+
~~~~~~~~~~~~~~~~~~~~
1789+
1790+
The ``MockResponse`` class comes with some helper methods to test the request:
1791+
1792+
* ``getRequestMethod()`` - returns the HTTP method;
1793+
* ``getRequestUrl()`` - returns the URL the request would be sent to;
1794+
* ``getRequestOptions()`` - returns an array containing other information about
1795+
the request such as headers, query parameters, body content etc.
1796+
1797+
Usage example::
1798+
1799+
$mockResponse = new MockResponse('', ['http_code' => 204]);
1800+
$httpClient = new MockHttpClient($mockResponse, 'https://example.com');
1801+
1802+
$response = $httpClient->request('DELETE', 'api/article/1337', [
1803+
'headers' => [
1804+
'Accept: */*',
1805+
'Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l',
1806+
],
1807+
]);
1808+
1809+
$mockResponse->getRequestMethod();
1810+
// returns "DELETE"
1811+
1812+
$mockResponse->getRequestUrl();
1813+
// returns "https://example.com/api/article/1337"
1814+
1815+
$mockResponse->getRequestOptions()['headers'];
1816+
// returns ["Accept: */*", "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l"]
1817+
1818+
Full Example
1819+
~~~~~~~~~~~~
1820+
1821+
The following standalone example demonstrates a way to use the HTTP client and
1822+
test it in a real application::
1823+
1824+
// ExternalArticleService.php
1825+
use Symfony\Contracts\HttpClient\HttpClientInterface;
1826+
1827+
final class ExternalArticleService
1828+
{
1829+
private HttpClientInterface $httpClient;
1830+
1831+
public function __construct(HttpClientInterface $httpClient)
1832+
{
1833+
$this->httpClient 8000 = $httpClient;
1834+
}
1835+
1836+
public function createArticle(array $requestData): array
1837+
{
1838+
$requestJson = json_encode($requestData, JSON_THROW_ON_ERROR);
1839+
1840+
$response = $this->httpClient->request('POST', 'api/article', [
1841+
'headers' => [
1842+
'Content-Type: application/json',
1843+
'Accept: application/json',
1844+
],
1845+
'body' => $requestJson,
1846+
]);
1847+
1848+
if (201 !== $response->getStatusCode()) {
1849+
throw new Exception('Response status code is different than expected.');
1850+
}
1851+
1852+
// ... other checks
1853+
1854+
$responseJson = $response->getContent();
1855+
$responseData = json_decode($responseJson, true, 512, JSON_THROW_ON_ERROR);
1856+
1857+
return $responseData;
1858+
}
1859+
}
1860+
1861+
// ExternalArticleServiceTest.php
1862+
use PHPUnit\Framework\TestCase;
1863+
use Symfony\Component\HttpClient\MockHttpClient;
1864+
use Symfony\Component\HttpClient\Response\MockResponse;
1865+
1866+
final class ExternalArticleServiceTest extends TestCase
1867+
{
1868+
public function testSubmitData(): void
1869+
{
1870+
// Arrange
1871+
$requestData = ['title' => 'Testing with Symfony HTTP Client'];
1872+
$expectedRequestData = json_encode($requestData, JSON_THROW_ON_ERROR);
1873+
1874+
$expectedResponseData = ['id' => 12345];
1875+
$mockResponseJson = json_encode($expectedResponseData, JSON_THROW_ON_ERROR);
1876+
$mockResponse = new MockResponse($mockResponseJson, [
1877+
'http_code' => 201,
1878+
'response_headers' => ['Content-Type: application/json'],
1879+
]);
1880+
1881+
$httpClient = new MockHttpClient($mockResponse, 'https://example.com');
1882+
$service = new ExternalArticleService($httpClient);
1883+
1884+
// Act
1885+
$responseData = $service->createArticle($requestData);
1886+
1887+
// Assert
1888+
self::assertSame('POST', $mockResponse->getRequestMethod());
1889+
self::assertSame('https://example.com/api/article', $mockResponse->getRequestUrl());
1890+
self::assertContains(
1891+
'Content-Type: application/json',
1892+
$mockResponse->getRequestOptions()['headers']
1893+
);
1894+
self::assertSame($expectedRequestData, $mockResponse->getRequestOptions()['body']);
1895+
1896+
self::assertSame($responseData, $expectedResponseData);
1897+
}
1898+
}
1899+
17721900
.. _`cURL PHP extension`: https://www.php.net/curl
17731901
.. _`PSR-17`: https://www.php-fig.org/psr/psr-17/
17741902
.. _`PSR-18`: https://www.php-fig.org/psr/psr-18/

0 commit comments

Comments
 (0)
0