PHPackages                             bbrothers/muzzle - 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. [HTTP &amp; Networking](/categories/http)
4. /
5. bbrothers/muzzle

ActiveLibrary[HTTP &amp; Networking](/categories/http)

bbrothers/muzzle
================

Guzzle Assertions on Requests and Responses

0.3.3(7y ago)54.8k1[1 PRs](https://github.com/bbrothers/muzzle/pulls)MITPHPPHP ~7.1

Since Apr 28Pushed 6y ago2 watchersCompare

[ Source](https://github.com/bbrothers/muzzle)[ Packagist](https://packagist.org/packages/bbrothers/muzzle)[ Docs](https://github.com/bbrothers/muzzle)[ RSS](/packages/bbrothers-muzzle/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (8)Dependencies (8)Versions (10)Used By (0)

Muzzle
======

[](#muzzle)

[![Latest Version on Packagist](https://camo.githubusercontent.com/6132b03f5e206fa2dc608a7b68075ea7c622bd81c7729a3c12131fecb0213ece/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6262726f74686572732f6d757a7a6c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bbrothers/muzzle)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Build Status](https://camo.githubusercontent.com/fa8de913e36dccd5c46fe9e562a33efec6271a27f7489079d17f228d5ac17b83/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f6262726f74686572732f6d757a7a6c652f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.org/bbrothers/muzzle)[![Coverage Status](https://camo.githubusercontent.com/3e05e75a43618e664dab24315f811572ee29f83ec723af6dcaac0be2f6a2b4d7/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f636f7665726167652f672f6262726f74686572732f6d757a7a6c652e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/bbrothers/muzzle/code-structure)[![Quality Score](https://camo.githubusercontent.com/d4e09864f57d0e4a1ac79455218280f8d723b990c6a050e6b4f0c4cd4d685acd/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f6262726f74686572732f6d757a7a6c652e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/bbrothers/muzzle)[![Total Downloads](https://camo.githubusercontent.com/bcf5e2464b2bb0f115346042db5af22dee196e2119559a0fff76da23e95e8b5e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6262726f74686572732f6d757a7a6c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/bbrothers/muzzle)

An experiment into the usefulness of assertions on Guzzle Requests and Responses. This code is mostly pulled from hack sessions and is not fully tested or ready for production use.

Install
-------

[](#install)

Via Composer

```
$ composer require bbrothers/muzzle
```

Usage
-----

[](#usage)

Use the fluent builder to define a set of expected requests and mock responses:

```
$client = Muzzle::builder()
                ->post('https://example.com/contact')
                ->json(['name' => 'Jane Doe'])
                ->replyWith(new Response(HttpStatus::CREATED))
                ->get('https://example.com/contact')
                ->query(['name' => 'Jane Doe'])
                ->build();

$this->assertInstanceOf(Muzzle::class, $client);
$client->post('https://example.com');
$client->get('https://example.com');
```

If not specified responses will default to an empty `200`.

The `expect` method can be used to pass pre-built `Exception` instances:

```
$createUser = (new Expectation)
    ->post('users')
    ->json(['name' => 'Jane', 'email' => 'j.doe@example.com'])
    ->replyWith((new ResponseBuilder)->setJson(User::make([
        'name' => 'Jane',
        'email' => 'j.doe@example.com'
    ])->toArray());

$client = Muzzle::builder()->expect($createUser)->build();
```

Expectations can also be added directly to the `Muzzle` instance by using the `append` method:

```
$client = new Muzzle;
$expectations = [];
for ($i = 0; $i < 10; $i++) {
    $expectations[] = (new Expectation)
        ->get("users/{$i}")
        ->replyWith((new ResponseBuilder)->setJson(['number' => $i]));
}
$client->append(...$expectations);
```

By default `Muzzle` will expect that a request was made and return an empty `200` response.

There are several pre-defined expectations available on the builder or `Expectation` class directly:

- `method`: accepts a variadic list of HTTP methods and asserts the actual request method is in the provided list.
- `uri`: accepts a URI, path or regex pattern to match the actual request against.
- `headers`: accepts an array of headers. They can be either the header name or a key/value pair of header name/expected value and will assert that all headers match the provided values.
- `query`: accepts an array of query parameters expected to be contained in the request. Parameters should be passed as an associative array of `[$name => $value]`, with the value optionally being a regex pattern.
- `queryShouldEqual`: like `query` this method accepts an associative array of parameters, however these must match exactly (with the exception of the order) with the actual request.
- `body`: accepts a string, array, `StreamInterface` instance or a regex pattern. If an array is given and the actual request is not json, it will `json_encode` the array and look for an exact match. If the actual request is JSON, it will decode it and use the same matching strategy as the `query` method, allowing for regex patterns as values. When a JSON string is provided, it will be decoded and treated the same as an array.
- `json`: accepts an array and delegates to the `body` method.
- `bodyShouldEqual`: accepts a string or string castable object, such as a `StreamInterface` instance, and asserts that it is an exact match to the actual request body.
- `should`: accepts a `callable` and provides the actual request as an `AssertableRequest` instance and the `Muzzle` instance as parameters when invoking the `callable`. The `callable` is expected be a `void` return type, so any return value will be ignored. See below for details.

Custom assertion rules can be added to an `Expectation` by calling the `should` method with a `callable` that implements the `Assertion` interface. When the `Assertion` is run, the recorded request will be passed to the `__invkoke` method as an `AssertableRequest` instance. The `Muzzle` instance is also passed as an optional second parameter.

```
class ContainJson implements Assertion {
   public function __consturct(array $content)
   {
       $this->expected = $expected;
   }
   public function __invoke(AssertableRequest $actual) : void
   {
        $actual->assertJson($this->expected);
   }
}
// then

(new Expectation)->should(new ContainJson(['name' => 'Jane Doe']));
```

Or as just a callback:

```
$expected = ['name' => 'Jane Doe'];
(new Expectation)->should(function (AssertableRequest $actual) use ($expected) : void {
    $actual->assertJson($expected);
});
```

Additional assertions can also be run on any responses from `Muzzle` or on requests/responses from the transaction history:

```
$client = Muzzle::builder()
                ->post('https://example.com/contact')
                ->json(['name' => 'Jane Doe'])
                ->replyWith(new Response(HttpStatus::CREATED))
                ->get('http://example.com/contact')
                ->query(['name' => 'Jane Doe'])
                ->replyWith(new Response(HttpStatus::MOVED_PERMANENTLY))
                ->build();

$this->assertInstanceOf(Muzzle::class, $client);
$client->post('https://example.com/contact')->assertSuccessful();
$client->get('http://example.com/contact')->assertRedirect('https://example.com/contact');

$client->lastRequest()->assertUriQueryNotHasKey('age');
```

Change log
----------

[](#change-log)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Testing
-------

[](#testing)

```
$ composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) and [CODE\_OF\_CONDUCT](CODE_OF_CONDUCT.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Brad Brothers](https://github.com/bbrothers)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity23

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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 ~41 days

Recently: every ~57 days

Total

8

Last Release

2647d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2eb217c8629a63fa37a8b673d77f4c95137a5399c98a9c25463afee2a5416e93?d=identicon)[bbrothers](/maintainers/bbrothers)

---

Top Contributors

[![bbrothers](https://avatars.githubusercontent.com/u/2477338?v=4)](https://github.com/bbrothers "bbrothers (59 commits)")

---

Tags

Guzzleassertionsbbrothersmuzzlehttp testing

###  Code Quality

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/bbrothers-muzzle/health.svg)

```
[![Health](https://phpackages.com/badges/bbrothers-muzzle/health.svg)](https://phpackages.com/packages/bbrothers-muzzle)
```

###  Alternatives

[graham-campbell/guzzle-factory

Provides A Simple Guzzle Factory With Good Defaults

916.4M49](/packages/graham-campbell-guzzle-factory)[bilfeldt/laravel-http-client-logger

A logger for the Laravel HTTP Client

1531.6M3](/packages/bilfeldt-laravel-http-client-logger)[kozz/laravel-guzzle-provider

Guzzle 5/6 Service Provider for Laravel

621.1M2](/packages/kozz-laravel-guzzle-provider)[onlime/laravel-http-client-global-logger

A global logger for the Laravel HTTP Client

1935.1k](/packages/onlime-laravel-http-client-global-logger)[wppconnect-team/wppconnect-laravel-client

A simple API with Guzzle wrapper, providing easy access to wppconnect's endpoints.

403.4k](/packages/wppconnect-team-wppconnect-laravel-client)[remic/guzzlecache

Laravel 5 package for caching Guzzle's GET requests.

189.3k](/packages/remic-guzzlecache)

PHPackages © 2026

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