@@ -1387,12 +1387,27 @@ This allows using them where native PHP streams are needed::
1387
1387
// later on if you need to, you can access the response from the stream
1388
1388
$response = stream_get_meta_data($streamResource)['wrapper_data']->getResponse();
1389
1389
1390
- Testing HTTP Clients and Responses
1391
- ----------------------------------
1390
+ Testing
1391
+ -------
1392
1392
1393
1393
This component includes the ``MockHttpClient `` and ``MockResponse `` classes to
1394
- use them in tests that need an HTTP client which doesn't make actual HTTP
1395
- requests.
1394
+ use in tests that shouldn't make actual HTTP requests. Such tests can be
1395
+ useful, as they will run faster and produce consistent results, since they're
1396
+ not dependant on an external service. By not making actual HTTP requests there
1397
+ is no need to worry about the service being online or the request changing
1398
+ state, for example deleting a resource.
1399
+
1400
+ ``MockHttpClient `` implements the ``HttpClientInterface ``, just like any actual
1401
+ HTTP client in this component. When you type-hint with ``HttpClientInterface ``
1402
+ your code will accept the real client outside tests, while replacing it with
1403
+ ``MockHttpClient `` in the test.
1404
+
1405
+ When the ``request `` method is used on ``MockHttpClient ``, it will respond with
1406
+ the supplied ``MockResponse ``. There are a few ways to use it, as described
1407
+ below.
1408
+
1409
+ HTTP Client and Responses
1410
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
1396
1411
1397
1412
The first way of using ``MockHttpClient `` is to pass a list of responses to its
1398
1413
constructor. These will be yielded in order when requests are made::
@@ -1451,6 +1466,121 @@ However, using ``MockResponse`` allows simulating chunked responses and timeouts
1451
1466
1452
1467
$mockResponse = new MockResponse($body());
1453
1468
1469
+ Testing Request Data
1470
+ ~~~~~~~~~~~~~~~~~~~~
1471
+
1472
+ The examples above describe how to return desired response. What if you wanted
1473
+ to also test the request itself? ``MockResponse `` comes with a few helper
1474
+ methods:
1475
+
1476
+ * ``getRequestMethod() `` - returns the HTTP method
1477
+ * ``getRequestUrl() `` - returns the URL the request would be sent to
1478
+ * ``getRequestOptions() `` - returns an array containing other information about
1479
+ the request such as headers, query parameters, body content etc.
1480
+
1481
+ Usage example::
1482
+
1483
+ $mockResponse = new MockResponse('', ['http_code' => 204]);
1484
+ $httpClient = new MockHttpClient($mockResponse, 'https://example.com');
1485
+
1486
+ $response = $httpClient->request('DELETE', 'api/article/1337', [
1487
+ 'headers' => [
1488
+ 'Accept: */*',
1489
+ 'Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l',
1490
+ ],
1491
+ ]);
1492
+
1493
+ // returns "DELETE"
1494
+ $mockResponse->getRequestMethod();
1495
+
1496
+ // returns "https://example.com/api/article/1337"
1497
+ $mockResponse->getRequestUrl();
1498
+
1499
+ // returns ["Accept: */*", "Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l"]
1500
+ $mockResponse->getRequestOptions()['headers'];
1501
+
1502
+ Example
1503
+ ~~~~~~~
1504
+
1505
+ The following standalone example demonstrates a way to use HTTP client and
1506
+ test it in a real application::
1507
+
1508
+ // ExternalArticleService.php
1509
+ use Symfony\Contracts\HttpClient\HttpClientInterface;
1510
+
1511
+ final class ExternalArticleService
1512
+ {
1513
+ private HttpClientInterface $httpClient;
1514
+
1515
+ public function __construct(HttpClientInterface $httpClient)
1516
+ {
1517
+ $this->httpClient = $httpClient;
1518
+ }
1519
+
1520
+ public function createArticle(array $requestData): array
1521
+ {
1522
+ $requestJson = json_encode($requestData, JSON_THROW_ON_ERROR);
1523
+
1524
+ $response = $this->httpClient->request('POST', 'api/article', [
1525
+ 'headers' => [
1526
+ 'Content-Type: application/json',
1527
+ 'Accept: application/json',
1528
+ ],
1529
+ 'body' => $requestJson,
1530
+ ]);
1531
+
1532
+ if (201 !== $response->getStatusCode()) {
1533
+ throw new Exception('Response status code is different than expected.');
1534
+ }
1535
+
1536
+ // ... other checks
1537
+
1538
+ $responseJson = $response->getContent();
1539
+ $responseData = json_decode($responseJson, true, 512, JSON_THROW_ON_ERROR);
1540
+
1541
+ return $responseData;
1542
+ }
1543
+ }
1544
+
1545
+ // ExternalArticleServiceTest.php
1546
+ use PHPUnit\Framework\TestCase;
1547
+ use Symfony\Component\HttpClient\MockHttpClient;
1548
+ use Symfony\Component\HttpClient\Response\MockResponse;
1549
+
1550
+ final class ExternalArticleServiceTest extends TestCase
1551
+ {
1552
+ public function testSubmitData(): void
1553
+ {
1554
+ // Arrange
1555
+ $requestData = ['title' => 'Testing with Symfony HTTP Client'];
1556
+ $expectedRequestData = json_encode($requestData, JSON_THROW_ON_ERROR);
1557
+
1558
+ $expectedResponseData = ['id' => 12345];
1559
+ $mockResponseJson = json_encode($expectedResponseData, JSON_THROW_ON_ERROR);
1560
+ $mockResponse = new MockResponse($mockResponseJson, [
1561
+ 'http_code' => 201,
1562
+ 'response_headers' => ['Content-Type: application/json'],
1563
+ ]);
1564
+
1565
+ $httpClient = new MockHttpClient($mockResponse, 'https://example.com');
1566
+ $service = new ExternalArticleService($httpClient);
1567
+
1568
+ // Act
1569
+ $responseData = $service->createArticle($requestData);
1570
+
1571
+ // Assert
1572
+ self::assertSame('POST', $mockResponse->getRequestMethod());
1573
+ self::assertSame('https://example.com/api/article', $mockResponse->getRequestUrl());
1574
+ self::assertContains(
1575
+ 'Content-Type: application/json',
1576
+ $mockResponse->getRequestOptions()['headers']
1577
+ );
1578
+ self::assertSame($expectedRequestData, $mockResponse->getRequestOptions()['body']);
1579
+
1580
+ self::assertSame($responseData, $expectedResponseData);
1581
+ }
1582
+ }
1583
+
1454
1584
.. _`cURL PHP extension` : https://www.php.net/curl
1455
1585
.. _`PSR-17` : https://www.php-fig.org/psr/psr-17/
1456
1586
.. _`PSR-18` : https://www.php-fig.org/psr/psr-18/
0 commit comments