Supercharge your app or SDK with a testing library specifically for Guzzle

Overview


Full Documentation at guzzler.dev

Supercharge your app or SDK with a testing library specifically for Guzzle. Guzzler covers the process of setting up a mock handler, recording history of requests, and provides several convenience methods for creating expectations and assertions on that history.

Installation

composer require --dev --prefer-dist blastcloud/guzzler

Example Usage

<?php

use BlastCloud\Guzzler\UsesGuzzler;
use GuzzleHttp\Client;

class SomeTest extends TestCase
{
    use UsesGuzzler;

    public $classToTest;

    public function setUp(): void
    {
        parent::setUp();
    
        $client = $this->guzzler->getClient([
            /* Any configs for a client */
            "base_uri" => "https://example.com/api"
        ]);
        
        // You can then inject this client object into your code or IOC container.
        $this->classToTest = new ClassToTest($client);
    }

    public function testSomethingWithExpectations()
    {
        $this->guzzler->expects($this->once())
            ->post("/some-url")
            ->withHeader("X-Authorization", "some-key")
            ->willRespond(new Response(201));
    
        $this->classToTest->someMethod();
    }

    public function testSomethingWithAssertions()
    {
        $this->guzzler->queueResponse(
            new Response(204),
            new \Exception("Some message"),
            // any needed responses to return from the client.
        );
    
        $this->classToTest->someMethod();
        // ... Some other number of calls
    
        $this->guzzler->assertAll(function ($expect) {
            return $expect->withHeader("Authorization", "some-key");
        });
    }
}

Documentation

Full Documentation

License

Guzzler is open-source software licensed under the MIT License.

Comments
  • Question

    Question

    Hi,

    Great package :)

    I'm using guzzler package in one of my Laravel applications (first time).

    And my test looks like this:

    $this->guzzler->expects($this->exactly(1))
        ->get("/customerrssss")
        ->willRespond(
            new Response(
                201,
                [],
                '{ "test": "test" }'
            ));
    
    $client = $this->guzzler->getClient([
        "base_uri" => "https://api.mollie.com/v2/"
    ]);
    
    $apiClient = new MollieApiClient($client);
    
    $apiClient->setApiKey('test_dHar4XY7LxsDOtmnkVtjNVWXLSlXsM');
    
    Mollie::shouldReceive('api')
        ->once()
        ->andReturn(new MollieApiWrapper($this->app['config'], $apiClient));
    
    $response = $this->post('/api/register', [
        'city' => 'Den Bosch',
    ]);
    
    dd($response);
    

    The response is '{ "test": "test" }'. But I don't use the url /customerrssss but /customers in my controller.

    So it looks like it doesn't matter what url I provide I always get that response. What could I be doing wrong here ?

    Thanks!

    opened by larsjanssen6 4
  • ObjectInvocation found on PHPUnit 8.2.1

    ObjectInvocation found on PHPUnit 8.2.1

    Hi, thank you so much for this awesome package!!

    Running on PHPUnit 8.2.1 the following error is thrown:

    [Error] Class 'PHPUnit\Framework\MockObject\Invocation\ObjectInvocation' not found
    #1  /home/johan/Code/pascal/vendor/blastcloud/guzzler/src/Expectation.php:141
    #2  /home/johan/Code/pascal/vendor/blastcloud/guzzler/src/Guzzler.php:43
    ...
    

    The PHPUnit\Framework\MockObject\Invocation namespace was removed on version v8.2 but remains on v8.1.6.

    opened by llstarscreamll 3
  • Filter withRpc

    Filter withRpc

    #12

    Unfortunately, I could not make the correct name of the method due to the peculiarities of filter connecting mechanism.


    Example of error output:

    Expectation: 
    -----------------------------
    JSON-RPC 2.0: (POST /rpc) {
        "id": "123",
        "jsonrpc": "2.0",
        "method": "test-method",
        "params": {
            "a": 1,
            "b": 2
        }
    }
    
    opened by vanodevium 2
  • Error: Cannot instantiate interface PHPUnit\Framework\MockObject\Invocation

    Error: Cannot instantiate interface PHPUnit\Framework\MockObject\Invocation

    Hello, just discovered this package and it looks incredible. However I am having some issues, can't seem to locate the issue.

    Sample code:

    $this->guzzler->expects($this->once())
                ->get('/v2/balance')
                ->willRespond(new Response(401, [], '{}'));
    

    Error:

    Error: Cannot instantiate interface PHPUnit\Framework\MockObject\Invocation
    
    /Users/anton/Projects/project/project/vendor/blastcloud/chassis/src/Expectation.php:119
    /Users/anton/Projects/project/project/vendor/blastcloud/chassis/src/Chassis.php:33
    /Users/anton/Projects/project/project/vendor/blastcloud/guzzler/src/UsesGuzzler.php:37
    /Users/anton/Projects/project/project/vendor/blastcloud/guzzler/src/UsesGuzzler.php:3
    

    PHPUnit Version: 9.5.1 Guzzle Version: 7.2 Guzzler Version: 2.0.1 PHP Version: 7.4

    Any ideas?

    opened by antonhedling 2
  • JSON-RPC 2.0 mock

    JSON-RPC 2.0 mock

    Quite often we need to mock RPC requests.

    We can easily create a macro:

    Expectation::macro('withJsonRpc', function (Expectation $e, $endpoint, $method, $params, $id = null) {
    
        $json = [
            'jsonrpc' => "2.0",
            'method' => $method,
            'params' => $params,
        ];
    
        if ($id) {
            $json['id'] = $id;
        }
    
        return $e
            ->post($endpoint)
            ->withJson($json);
    });
    

    But, unfortunately, if we get an exception, then we cannot understand that it was exactly a call of withJsonRpc()

    How about creating a separate filter with own error message? Something like

    JSON-RPC
    Endpoint: /rpc
    Method:   POST
    Body: {
        "id": 123,
        "jsonrpc": "2.0",
        "method": "test-method",
        "params": {
            "a": 1,
            "b": 2
        }
    }
    
    opened by vanodevium 1
  • Feedback Wanted [Proposal] Phase 3 Project: Road Test

    Feedback Wanted [Proposal] Phase 3 Project: Road Test

    Please either leave a thumbs up, thumbs down, or any other reaction, or respond with a comment.

    For the next phase of Guzzler, I'd really appreciate feedback from anyone interested in the project. For a full description of an upcoming project Road Test, please see the related page on the documentation site; Road Test

    This idea is very strongly based on PHPUnit's coverage report. However, instead of keeping track of lines of code executed in a test, it would keep track of endpoints hit and response codes returned from those endpoints. By doing so, a report can be generated afterwards that your code is in fact accounting for each endpoint you intent to, and any error status codes you want to ensure are accounted for. For example, you can verify your code handles responses for 200, 500, and any other status code from the endpoint /example/api/v2/companies/14968.

    This project would need to come after Drive is completed enough to handle recording of endpoints and statuses. If Drive can be thought of as a mechanism to do contract testing, then Road Test is the result and proof that all corners are covered that were wanted.

    Again, please leave a reaction or any thoughts on this issue. Feedback is helpful.

    Feedback Requested 
    opened by adamkelso 1
  • Feedback Wanted [Proposal] Phase 2 Project: Drive

    Feedback Wanted [Proposal] Phase 2 Project: Drive

    Please either leave a thumbs up, thumbs down, or any other reaction, or respond with a comment.

    For the next phase of Guzzler, I'd really appreciate feedback from anyone interested in the project. For a full description of the next project Drive, please see the related page on the documentation site; Drive

    The basic idea is a response factory system for a your tests based on either a Swagger/OpenAPI, RAML, or Blueprint API spec doc provided by any service you want to interact with. For example, you might want to integrate with an invoicing service. If so, you may want to specify what your code expects back from a GET endpoint for querying an invoice.

    You may build out something like the following:

    use function BlastCloud/Drive/drive;
    
    class SomeTest extends TestCase
    {
    // ...
    
        $this->guzzler->expects($this->once())
            ->get('/v3/company/{$this->companyId}/invoice/{$this->itemId}')
            ->willRespond( drive('invoice-fountain.invoices.get', 200) );
    

    By default, any data specified in the spec would auto-fill to the same structure with data provided by Faker. You could also fill anything specific you'd like returned, much like Laravel's Model Factories.

    //...
    
    $this->guzzler->expects($this->once())
        ->get('/v3/company/{$this->companyId}/invoice/{$this->itemId}')
        ->willRespond( 
            drive('invoice-fountain.invoice.get', 200)
                ->json([
                    'data' => drive('invoice-fountain.invoice', [
                        'customer_id' => 42,
                        'date_issued' => $faker->dateThisYear()
                    ])
                ])
        );
    

    Again, please leave a reaction or any thoughts on this issue. Feedback is helpful.

    Feedback Requested 
    opened by adamkelso 1
  • Add custom message to `withCallback()`

    Add custom message to `withCallback()`

    Currently, the API for withCallback() accepts one argument, the closure to filter the history items. A second one should be added so that the user can pass a more helpful message for what their closure is actually checking.

    // Before
    $expectation->withCallback(function ($history) { 
       /* something */ 
       return bool;
    });
    
    // After
    $expectation->withCallback(function ($history) {
        return bool;
    }, "Failed asserting that the Rhinos are just overweight unicorns.");
    
    enhancement 
    opened by adamkelso 1
  • Add `withGraphQL` Filter

    Add `withGraphQL` Filter

    • [ ] Lookup GraphQL Spec
    • [ ] Figure out what can be easily supported from a filter perspective
      • [ ] Some of the internal functions could make for an unfriendly API on the Guzzler side
      • [ ] If it can be done just off of the final query string, it should be fine, but will need some work on the API friendliness.
    • [ ] Create a WithGraphQL filter file.
    • [ ] Build out class and tests.
    • [ ] May require the most complex __toString() method thus far.
    enhancement 
    opened by adamkelso 1
  • Write `Roadmap` page in docs

    Write `Roadmap` page in docs

    Include:

    • [x] Make outline to fill out

    • [x] Idea for Drive

      • [x] For working with OpenAPI and others docs
      • [x] Response factories modeled after Laravel model factories
      • [x] validate() method on expectations.
      • [x] Possible syntaxes
    • [x] Idea for MPG

      • [x] Show PHPUnit coverage report as example
      • [x] Show possible idea for report
      • [x] Mention new coverage standard that would be needed.
    documentation 
    opened by adamkelso 1
  • Add examples of common scenarios

    Add examples of common scenarios

    • [x] Simple get request(s) : Google Maps
    • [x] Asynchronous / Promise based code : Google Street view
    • [ ] Working with forms (both URL encoded and multipart) : Stripe
    • [ ] Uploading Files : S3
    • [x] Handling failure scenarios
    documentation 
    opened by adamkelso 0
  • More examples

    More examples

    Hi!

    I've seen this issue being closed while there are still quite a few places in the docs that do not have examples https://github.com/blastcloud/guzzler/issues/3

    Do you plan to add those ?

    Particularly, I took quite a while to figure out how to test multi-part forms that contains file, as I was trying to use the withBody method combined with a MultipartStream object.

    My final solution here is the following, if anyone have the same needs:

    $filepath = dirname(__FILE__) . '/../assets/asset1.jpg';
    $this->guzzler
        ->expects($this->once())
        ->post('/assets/')
        ->withHeader('Authorization', 'Bearer ' . $this->fakeToken)
        ->withForm([
              'my_field_1' => 1,
              'my_field_2' => 'my_value',
         ])
         ->withFile('file', new File(Utils::tryFopen($filepath, 'r')))
         ->willRespond(new Response(409, [], ''));
    
    opened by oxodao 1
Releases(2.0.3)
  • 2.0.3(Dec 27, 2022)

    [2.0.3] - 2022-12-27

    • Add support for PHP 8.2, remove support for 7.4
    • Force update to Guzzle version 7.4.3 to handle security issue.
    • Update version of Chassis, underlying engine from BlastCloud
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Jan 18, 2022)

    • Adding a new filter withRpc, to ensure the request properly fits the JSONRPC spec.
      • Thanks @webdevium for the pull request.
    • Testing on PHP 8.1
    • Drops support for PHP versions below 7.4
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Dec 5, 2020)

  • 2.0.0(Jun 29, 2020)

  • 1.6.1(Mar 10, 2020)

  • 1.6.0(Jan 10, 2020)

    [1.6.0] - 2020-01-10

    • Updating CI to test on PHP 7.4
      • This will be the last release supporting PHP 7.1
    • Added new methods: withoutQuery, withQueryKey, and withQueryKeys
    Source code(tar.gz)
    Source code(zip)
  • 1.5.3(Oct 4, 2019)

    [1.5.3] - 2019-10-03

    • Moved codebase to build on blastcloud/chassis. Chassis is the abstracted expectation engine that was originally built for Guzzler. Now, Chassis can be used as a common base for any number of testing libraries for different PHP HTTP request clients. Check out Hybrid, a port of Guzzler for Symfony's HttpClient component.
    • Added the ability to rename the engine in test files if desired. You no longer have to have the engine named guzzler if you'd rather it be named something else. See the docs here.
    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(Jun 10, 2019)

    [1.5.2] - 2019-06-10

    • Fixed the deprecated/removed ObjectInvocation in PHPUnit 8.2 and above installations.
      • Thanks @llstarscreamll for reporting the bug.
    Source code(tar.gz)
    Source code(zip)
  • 1.5.1(May 20, 2019)

    [1.5.1]

    • Added the ability to add a custom error message for withCallback.
    • Fixed the json_encode formatting for the error message on withQuery.
    • Various updates to the documentation.
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(May 4, 2019)

    [Unreleased]

    • I plan to write and release a road map document on the docs site outlining where I want to go with the next project, tentatively called Drive, that will work with Guzzler. The short description of it is, "Response factories based on Swagger, RAML, or API Blueprint docs".

    [1.5.0]

    • Added the withFile filter. Includes several new tests and a File helper object.
    • Added the withCallback filter which allows users to pass an arbitrary anonymous function to filter history items.
    Source code(tar.gz)
    Source code(zip)
  • 1.4.2(Apr 21, 2019)

  • 1.4.1(Apr 4, 2019)

  • 1.4.0(Apr 4, 2019)

    • Added the ability to add custom macros.
    • Added an extension class that can be added to a phpunit.xml file to globally load both a custom filter namespace and a macros file.
    Source code(tar.gz)
    Source code(zip)
  • 1.3.0(Mar 25, 2019)

    • Added Exposition::addNamespace method to allow users to write custom filters and override Guzzler provided filters.
    • Refactored Exposition::__call method to search through any user-provided namespaces for filters before using the defaults provided by Guzzler.
    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Mar 23, 2019)

    This is a major refactor release. However, the APIs are either exactly the same or are modified in ways that will not break existing usage. See the CHANGELOG.md file for full details.

    This refactor was necessary for the exciting ideas I have for the next release and beyond.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Mar 16, 2019)

  • 1.1.0(Mar 3, 2019)

    • Adding the new synchronous and asynchronous methods to the Expectation class.
    • Updating the marketing slogan to "Supercharge" instead of "Simplify".
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Mar 3, 2019)

  • 1.0.0(Feb 28, 2019)

Guzzle, an extensible PHP HTTP client

Guzzle, PHP HTTP client Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and trivial to integrate with web services. Simple interf

Guzzle 22.3k Jan 2, 2023
Simple handler system used to power clients and servers in PHP (this project is no longer used in Guzzle 6+)

RingPHP Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function. RingPHP be used to power HTTP clie

Guzzle 846 Dec 6, 2022
A HTTP Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack.

A HTTP Cache for Guzzle 6. It's a simple Middleware to be added in the HandlerStack.

Kevin Robatel 371 Dec 17, 2022
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.

Requests for PHP Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python librar

null 3.5k Dec 31, 2022
Creating an all in one AI with a web UI to control it. Create your own AI server and/or sell API keys to other people to use your AI.

+ Currently taking an hour or two break to spend some time with the wife. - Then going to work on auto refreshing the chat and document ingestion so y

null 10 Jun 14, 2023
Unirest in PHP: Simplified, lightweight HTTP client library.

Unirest for PHP Unirest is a set of lightweight HTTP libraries available in multiple languages, built and maintained by Mashape, who also maintain the

Kong 1.3k Dec 28, 2022
The best php curl library.

中文文档 About Implemented by using php-curl internal io event with high performance,high universality,high extensibility which especially suitable for ma

Ares 431 Dec 12, 2022
PHP Secure Communications Library

phpseclib - PHP Secure Communications Library Supporting phpseclib Become a backer or sponsor on Patreon One-time donation via PayPal or crypto-curren

null 4.9k Jan 3, 2023
Custom PHP curl library for the Laravel 5 framework - developed by Ixudra

ixudra/curl Custom PHP cURL library for the Laravel 4 or 5 framework - developed by Ixudra. The package provides an easy interface for sending cURL re

Jan Oris 556 Jan 6, 2023
A modern PHP library that allows you to make resilient calls to external services

Resiliency, an implementation for resilient and modern PHP applications Main principles This library is compatible with PHP 7.4+. Installation compose

We love open source softwares 77 Dec 12, 2022
This library provides an object-oriented wrapper of the PHP cURL extension

PHP Curl Class This library provides an object-oriented wrapper of the PHP cURL extension. If you have questions or problems with installation or usag

PHP MOD 321 Dec 30, 2022
The best php curl library.

中文文档 About Implemented by using php-curl internal io event with high performance,high universality,high extensibility which especially suitable for ma

Ares 431 Dec 12, 2022
LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent Netty event-based networking library

LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent Netty event-based networking library

null 1.9k Dec 26, 2022
Requests - a HTTP library written in PHP, for human beings

Requests is a HTTP library written in PHP, for human beings. It is roughly based on the API from the excellent Requests Python library. Requests is ISC Licensed (similar to the new BSD license) and has no dependencies, except for PHP 5.6+.

WordPress 3.5k Jan 6, 2023
The Library for HTTP Status Codes, Messages and Exception

This is a PHP library for HTTP status codes, messages and error exception. Within the library, HTTP status codes are available in classes based on the section they belong to. Click this link for more information.

Sabuhi Alizada 5 Sep 14, 2022
A library that makes the management of WordPress file headers easier.

Pronamic WordPress File Header Many WordPress plugins contain bash scripts with sed and awk commands to update WordPress file headers. Because sed and

Pronamic 3 Oct 6, 2022
Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.

This is a port of the VCR Ruby library to PHP. Record your test suite's HTTP interactions and replay them during future test runs for fast, determinis

php-vcr 1.1k Dec 23, 2022
Transform your WordPress site into a modern GraphQL server: graphql-api.com.

GraphQL API for WordPress Transform your WordPress site into a modern GraphQL server: graphql-api.com. This plugin is the implementation for WordPress

GraphQL API 151 Dec 14, 2022