How to mock responses for specific URLs with Guzzle?
Asked Answered
S

2

10

The Guzzle 6 documentation gives an easy way to mock HTTP calls so that each request returns a specific response : http://docs.guzzlephp.org/en/latest/testing.html#mock-handler

However, as it is stated in the documentation, the MockHandler defines a queue of responses that will be sent for each request, whatever the URL, in the same order.

How to tell Guzzle to send a specific response for a given URL, each time it is called?

For instance, I want this call:

$client->request('GET', '/products')->getBody();

not to make the actual request but to always return:

{'products' => [{id: 1, name: 'Product 1'}, {id: 2, name: 'Product 2'}]

Doing it with the AngularJS $httpBackend service would be easy:

$httpBackend
    .when('GET', '/products')
    .respond("{id: 1, name: 'Product 1'}, {id: 2, name: 'Product 2'}")

Any idea on how to achieve this with Guzzle 6?

Schlenger answered 9/10, 2015 at 7:7 Comment(4)
Are you able to provide some context concerning to test setup or the application in general? I'm trying to understand why you would need make more then one call to any particular url, especially if you simply want to return identical responses.Scrap
@ShaunBramley I am doing functional tests with Behat and Mink. So I load a page of my website in the test (e.g. Given I am on /catalog) which is a page that makes several calls to an external API (a call to get products and a call to get latest news for instance) with Guzzle and I don't necessary know the order of calls. And I would not like my test to depend on the external API during my tests (which may be down, slow, or whatever), as this is the page I want to test (it should display the products / news from the API), not the API itself. This is the context!Sanmicheli
I am looking for the same solution. I found this library: github.com/eschwartz/GuzzleHttpMock (it currently supports guzzle 5, I wonder if it supports 6 branch)Fritzie
URLs (fixed and regexps-based) mock handler for Guzzle 6 - tarampampam/guzzle-url-mockEben
A
5

With guzzle 6 you can also use a function as a handler! and the function passes the Request object so you can check the URL and return the proper response.

example:

        $client = new Client([
            'handler' => function (GuzzleHttp\Psr7\Request $request) {
                $path = $request->getUri()->getPath();

                if ($path === '/url1') {
                    return new GuzzleHttp\Psr7\Response(200, [], '{"body": "Url1"}');
                }

                if ($path === '/url2') {
                    return new GuzzleHttp\Psr7\Response(200, [], '{"body": "Url2"}');
                }
            }
        ]);

        $client->get('/url1');

I hope this helped someone.

Archivolt answered 14/11, 2021 at 15:37 Comment(0)
C
0

If you do acceptance testing with Behat and Mink, the best option is not to touch the application code itself but mock (stub) external resources outside the app. For example, if you want to mock Twitter for your app, it's better to create a separated webapp (with mocks (stubs) inside) and pass its URL to your app (SUT).

Take a look on HTTP Mock for PHPUnit: it does exactly this, but works only with PHPUnit at this moment. API is very similar to AngularJS:

$this->http->mock
    ->when()
        ->methodIs('GET')
        ->pathIs('/foo')
    ->then()
        ->body('mocked body')
    ->end();
$this->http->setUp();
Christenson answered 22/7, 2016 at 15:3 Comment(1)
That's interesting, thanks! It seems to do what I am looking for.I'll have a look at it.Sanmicheli

© 2022 - 2024 — McMap. All rights reserved.