@@ -1279,7 +1279,7 @@ Symfony's HTTP client provides an EventSource implementation to consume these
1279
1279
server-sent events. Use the :class: `Symfony\\ Component\\ HttpClient\\ EventSourceHttpClient `
1280
1280
to wrap your HTTP client, open a connection to a server that responds with a
1281
1281
``text/event-stream `` content type and consume the stream as follows::
1282
-
1282
+
1283
1283
use Symfony\Component\HttpClient\Chunk\ServerSentEvent;
1284
1284
use Symfony\Component\HttpClient\EventSourceHttpClient;
1285
1285
@@ -1627,12 +1627,27 @@ has many safety checks that will throw a ``LogicException`` if the chunk
1627
1627
passthru doesn't behave correctly; e.g. if a chunk is yielded after an ``isLast() ``
1628
1628
one, or if a content chunk is yielded before an ``isFirst() `` one, etc.
1629
1629
1630
- Testing HTTP Clients and Responses
1631
- ----------------------------------
1630
+ Testing
1631
+ -------
1632
1632
1633
1633
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
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
1636
1651
1637
1652
The first way of using ``MockHttpClient `` is to pass a list of responses to its
1638
1653
constructor. These will be yielded in order when requests are made::
@@ -1769,6 +1784,119 @@ Then configure Symfony to use your callback:
1769
1784
;
1770
1785
};
1771
1786
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
+
1772
1900
.. _`cURL PHP extension` : https://www.php.net/curl
1773
1901
.. _`PSR-17` : https://www.php-fig.org/psr/psr-17/
1774
1902
.. _`PSR-18` : https://www.php-fig.org/psr/psr-18/
0 commit comments