PHPackages                             macpaw/extended\_mock\_http\_client - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. macpaw/extended\_mock\_http\_client

ActiveLibrary[Testing &amp; Quality](/categories/testing)

macpaw/extended\_mock\_http\_client
===================================

This repository provides mocks for Symfony HTTP Client, it more flexible than default Symfony mock

v4.0.1(2y ago)6292.7k↓35%1[1 PRs](https://github.com/MacPaw/extended_mock_http_client/pulls)1MITPHPPHP &gt;=8.1

Since Jun 21Pushed 2y ago2 watchersCompare

[ Source](https://github.com/MacPaw/extended_mock_http_client)[ Packagist](https://packagist.org/packages/macpaw/extended_mock_http_client)[ RSS](/packages/macpaw-extended-mock-http-client/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (16)Versions (33)Used By (1)

ExtendedMockHttpClient
======================

[](#extendedmockhttpclient)

VersionBuild StatusCode Coverage`master`[![CI](https://github.com/macpaw/ExtendedMockHttpClient/workflows/CI/badge.svg?branch=master)](https://github.com/macpaw/ExtendedMockHttpClient/actions?query=workflow%3ACI+branch%3Amaster)[![Coverage Status](https://camo.githubusercontent.com/cbf7211f2c84eedee536edaa7ee258d6604e6f12267dd09dbdeba91ec76ea7a6/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f6d61637061772f457874656e6465644d6f636b48747470436c69656e742f6d61737465723f6c6f676f3d636f6465636f76)](https://codecov.io/gh/macpaw/ExtendedMockHttpClient/branch/master)Install
-------

[](#install)

```
composer require macpaw/extended_mock_http_client
```

How to use
----------

[](#how-to-use)

In config file `config/services_test.yaml` replace current HTTP client service

```
imports:
    - { resource: services.yaml }

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: true
    http_client_service_name:
        class: ExtendedMockHttpClient\ExtendedMockHttpClient
        arguments:
            - 'https://test.host'
```

That's all, you can use it in PHPUnit tests

Examples
--------

[](#examples)

#### Simple examples

[](#simple-examples)

```
abstract class AbstractFunctionalTest extends KernelTestCase
{
    private ExtendedMockHttpClient $httpClient

    protected function setUp(): void
    {
        /** @var ExtendedMockHttpClient $mockHttpClient */
        $this->httpClient = self::getContainer()->get('http_client_service_name');
    }
}

class MyTest extends AbstractFunctionalTest
{
    /**
     * Create simple request using createFixture
     * Request with almost empty parameters
     * Check response and check called times
     */
    public function testSimpleExample1(): void
    {
        $httpFixture = $this->client->createFixture(
            'POST',
            'https://test.test/foo?foo=bar',
            null,
            null,
            200,
            'ok'
        );
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('POST', 'https://test.test/foo?foo=bar');

        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals('ok', $response->getContent());
        self::assertEquals(1, $httpFixture->getCalledTimes());
    }

    /**
     * Make simple fixture using createFixture
     * Request using json
     * Check response
     */
    public function testSimpleExample2(): void
    {
        $httpFixture = $this->client->createFixture(
            'POST',
            'https://test.test/foo?foo=bar',
            '{"foo":"bar","baz":123}',
            [
                'x-header' => 'x-value',
            ],
            200,
            'ok'
        );
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('POST', 'https://test.test/foo?foo=bar', [
            'json' => [
                'foo' => 'bar',
                'baz' => 123
            ],
            'headers' => [
                'x-header' => 'x-value',
            ]
        ]);

        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals('ok', $response->getContent());
    }
}
```

#### Using builder examples

[](#using-builder-examples)

```
class MyTest extends AbstractFunctionalTest
{
    /**
     * Make fixture using builder
     * Request using json
     * Check response
     */
    public function testBuilderExample1(): void
    {
        $builder = $this->client->getHttpFixtureBuilder();

        $httpFixture = $builder
            ->request(
                $builder->method(['PUT', 'POST']),
                $builder->url('https://test.test/foo'),
                $builder->query([
                    'foo' => 'bar',
                ]),
                $builder->body($builder->jsonToArray(
                    $builder->arrayContain([
                        'foo' => 'bar',
                    ])
                )),
                $builder->headers([
                    'x-header' => 'x-value',
                ])
            )
            ->response(200, 'ok')
            ->build();
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('POST', 'https://test.test/foo?foo=bar', [
            'json' => [
                'foo' => 'bar',
                'baz' => 123
            ],
            'headers' => [
                'x-header' => 'x-value',
            ]
        ]);

        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals('ok', $response->getContent());
    }

    /**
     * Make fixture using builder with MockResponse
     * Request using json
     * Check response
     */
    public function testBuilderExample2(): void
    {
        $builder = $this->client->getHttpFixtureBuilder();

        $httpFixture = $builder
            ->request(
                $builder->method('POST'),
                $builder->url('https://test.test/foo'),
                $builder->query($builder->queryToArray($builder->arrayContain([
                    'foo' => 'bar',
                ]))),
                $builder->body($builder->stringRegex('/"foo":"bar"/')),
                $builder->headers([
                    'x-header' => 'x-value',
                ])
            )
            ->response(new MockResponse('ok', ['http_code' => 200]))
            ->build();
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('POST', 'https://test.test/foo?foo=bar', [
            'json' => [
                'foo' => 'bar',
                'baz' => 123
            ],
            'headers' => [
                'x-header' => 'x-value',
            ]
        ]);

        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals('ok', $response->getContent());
    }
}
```

#### Using callbacks in request and response examples

[](#using-callbacks-in-request-and-response-examples)

```
class MyTest extends AbstractFunctionalTest
{
    /**
     * Make fixture using builder with callbacks in request and response
     * Request using json
     * Check response
     */
    public function testCallbackExample(): void
    {
        $builder = $this->client->getHttpFixtureBuilder();

        $httpFixture = $builder
            ->request(
                $builder->method($builder->callback(function (string $method): bool {
                    return $method === 'POST';
                })),
                $builder->url($builder->callback(function (string $url): bool {
                    return $url === 'https://test.test/foo';
                })),
                $builder->query(
                    $builder->callback(function (string $query): bool {
                        return $query === 'foo=bar';
                    }),
                    $builder->queryToArray(
                        $builder->callback(function (array $arrayQuery): bool {
                            return array_key_exists('foo', $arrayQuery);
                        })
                    )
                ),
                $builder->body($builder->callback(function (string $jsonBody): bool {
                    $arrayBody = json_decode($jsonBody, true);

                    return isset($arrayBody['foo']);
                })),
                $builder->headers($builder->callback(function (array $headers): bool {
                    return array_key_exists('x-header', $headers);
                }))
            )
            ->response(
                function (string $method, string $url, string $query, string $body, array $headers): MockResponse {
                    $stringHeaders = [];
                    foreach ($headers as $key => $value) {
                        $stringHeaders[] = "$key: $value";
                    }

                    return new MockResponse(json_encode([
                        'method' => $method,
                        'url' => $url,
                        'query' => $query,
                        'body' => $body,
                        'headers' => $headers,
                    ]));
                }
            )
            ->build();
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('POST', 'https://test.test/foo?foo=bar', [
            'json' => [
                'foo' => 'bar',
                'baz' => 123
            ],
            'headers' => [
                'x-header' => 'x-value',
            ]
        ]);

        self::assertEquals(200, $response->getStatusCode());

        $responseArray = json_decode($response->getContent(), true);
        self::assertEquals('POST', $responseArray['method']);
        self::assertEquals('https://test.test/foo', $responseArray['url']);
        self::assertEquals('foo=bar', $responseArray['query']);
        self::assertEquals('{"foo":"bar","baz":123}', $responseArray['body']);
        self::assertArrayHasKey('x-header', $responseArray['headers']);
    }
}
```

#### Hot to register custom Comparator

[](#hot-to-register-custom-comparator)

Create comparator class, it should implement `ComparatorInterface`

```
use ExtendedMockHttpClient\HttpFixture\Request\Comparator\ComparatorInterface;

class CustomComparator implements ComparatorInterface
{
    /**
     * @var string
     */
    private $stringPart1;

    /**
     * @var string
     */
    private $stringPart2;

    public static function getName(): string
    {
        return 'custom';
    }

    public function __construct(string $stringPart1, string $stringPart2)
    {
        $this->stringPart1 = $stringPart1;
        $this->stringPart2 = $stringPart2;
    }

    public function __invoke($value): bool
    {
        return $value === "$this->stringPart1.$this->stringPart2";
    }
}
```

Overwrite `HttpFixtureFactory` for adding where you can use the new comparator

```
services:
    ExtendedMockHttpClient\Factory\HttpFixtureFactory:
        arguments:
            - '%allowed_nested_keys%'
        calls:
            - add: ['body', 'custom']
            - add: ['method', 'custom']
            - add: ['query', 'custom']
            ...
```

Use the new comparator in test

```
class MyTest extends AbstractFunctionalTest
{
    /**
     * Make fixture using builder with custom comparator
     * Request using string body
     * Check response
     */
    public function testCustomComparator(): void
    {
        $builder = $this->client->getHttpFixtureBuilder();

        $httpFixture = $builder
            ->request(
                $builder->body(new CustomComparator('foo', 'bar'))
            )
            ->response(200, 'ok')
            ->build();
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('GET', 'https://test.test', [
            'body' => 'foo.bar'
        ]);

        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals('ok', $response->getContent());
    }
}
```

#### Hot to overwrite HttpFixtureBuilderFactory for using more useful builder method

[](#hot-to-overwrite-httpfixturebuilderfactory-for-using-more-useful-builder-method)

Create custom builder class which based on original builder

```
use ExtendedMockHttpClient\Builder\HttpFixtureBuilder as BaseHttpFixtureBuilder;
use ExtendedMockHttpClient\Tests\Fixture\Application\HttpFixture\Request\Comparator\CustomComparator;

class HttpFixtureBuilder extends BaseHttpFixtureBuilder
{
    public function custom(string $stringPart1, string $stringPart2): CustomComparator
    {
        return new CustomComparator($stringPart1, $stringPart2);
    }
}
```

Create custom builder factory class which based on original builder factory

```
use ExtendedMockHttpClient\Factory\HttpFixtureBuilderFactory as BaseHttpFixtureBuilderFactory;
use ExtendedMockHttpClient\Builder\HttpFixtureBuilder as BaseHttpFixtureBuilder;
use ExtendedMockHttpClient\Tests\Fixture\Application\Builder\HttpFixtureBuilder;

class HttpFixtureBuilderFactory extends BaseHttpFixtureBuilderFactory
{
    public function create(): BaseHttpFixtureBuilder
    {
        return new HttpFixtureBuilder($this->httpFixtureFactory);
    }
}
```

Overwrite builder factory service

```
services:
    ExtendedMockHttpClient\Factory\HttpFixtureBuilderFactory:
        class: ExtendedMockHttpClient\Tests\Fixture\Application\Factory\HttpFixtureBuilderFactory
```

Use updated builder in tests

```
class MyTest extends AbstractFunctionalTest
{
    /**
     * Make fixture using overwrote builder with custom comparator
     * Request using string body
     * Check response
     */
    public function testBuilderOverwrote(): void
    {
        /** @var HttpFixtureBuilder $builder */
        $builder = $this->client->getHttpFixtureBuilder();

        $httpFixture = $builder
            ->request(
                $builder->body($builder->custom('foo', 'bar'))
            )
            ->response(200, 'ok')
            ->build();
        $this->client->addFixture($httpFixture);

        $response = $this->client->request('GET', 'https://test.test', [
            'body' => 'foo.bar'
        ]);

        self::assertEquals(200, $response->getStatusCode());
        self::assertEquals('ok', $response->getContent());
    }
}
```

Todo list
---------

[](#todo-list)

- Add support jms serializer
- Add history function
    - Get last request/response (or by index)
    - Some kind of assert, it should check that history contain some request
- Add possibility to load fixtures from array/yaml
- Add logger and log every steps for easiest debug

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity39

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity75

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~42 days

Recently: every ~159 days

Total

32

Last Release

854d ago

Major Versions

1.0.17 → 2.0.02020-12-23

v2.6.0 → v3.0.02022-04-18

v3.1.1 → v4.0.02023-05-03

PHP version history (4 changes)1.0.0PHP ^7.1

2.0.0PHP &gt;=7.2

v3.0.0PHP ^7.2|^7.3|^7.4|^8.0|^8.1

v4.0.0PHP &gt;=8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1935412?v=4)[MacPaw Inc.](/maintainers/macpaw)[@MacPaw](https://github.com/MacPaw)

![](https://www.gravatar.com/avatar/415a6c5f079859104abefc3592ee26337cfdb8466a98d1fadcd010072414523e?d=identicon)[Yozhef](/maintainers/Yozhef)

![](https://www.gravatar.com/avatar/0353c785cf2048e5bd73d1a0ad16d5f252000e02b28f0d89b358e93fa9329dce?d=identicon)[alekseytupichenkov](/maintainers/alekseytupichenkov)

---

Top Contributors

[![alekseytupichenkov](https://avatars.githubusercontent.com/u/8191991?v=4)](https://github.com/alekseytupichenkov "alekseytupichenkov (67 commits)")[![Yozhef](https://avatars.githubusercontent.com/u/8971757?v=4)](https://github.com/Yozhef "Yozhef (62 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![semantic-release-bot](https://avatars.githubusercontent.com/u/32174276?v=4)](https://github.com/semantic-release-bot "semantic-release-bot (4 commits)")[![anasinnyk](https://avatars.githubusercontent.com/u/23741265?v=4)](https://github.com/anasinnyk "anasinnyk (3 commits)")[![artemlive](https://avatars.githubusercontent.com/u/3328394?v=4)](https://github.com/artemlive "artemlive (2 commits)")

---

Tags

backendfixtureshttp-clientmacpawmockphpunitsymfonytestingtestingsymfonyhttp clientfixturesmockdevelopment

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/macpaw-extended-mock-http-client/health.svg)

```
[![Health](https://phpackages.com/badges/macpaw-extended-mock-http-client/health.svg)](https://phpackages.com/packages/macpaw-extended-mock-http-client)
```

###  Alternatives

[behat/behat

Scenario-oriented BDD framework for PHP

4.0k96.8M2.0k](/packages/behat-behat)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.4k5.6M651](/packages/sylius-sylius)[simplesamlphp/simplesamlphp

A PHP implementation of a SAML 2.0 service provider and identity provider.

1.1k12.4M193](/packages/simplesamlphp-simplesamlphp)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
