Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HttpClient] add MockHttpClient #30604

Merged
merged 1 commit into from Mar 19, 2019

Conversation

Projects
None yet
6 participants
@nicolas-grekas
Copy link
Member

commented Mar 19, 2019

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets -
License MIT
Doc PR -

This PR introduces MockHttpClient and MockResponse, to be used for testing classes that need an HTTP client without making actual HTTP requests.

MockHttpClient is configured via its constructor: you provide it either with an iterable or a callable, and these will be used to provide responses as the consumer requests them.

Example:

$responses = [
    new MockResponse($body1, $info1),
    new MockResponse($body2, $info2),
];

$client = new MockHttpClient($responses);
$response1 = $client->request(...); // created from $responses[0]
$response2 = $client->request(...); // created from $responses[1]

Or alternatively:

$callback = function ($method, $url, $options) {
    return new MockResponse(...);
};

$client = new MockHttpClient($callback);
$response = $client->request(...); // calls $callback internally

The responses provided to the client don't have to be instances of MockResponse - any ResponseInterface works (e.g. $this->getMockBuilder(ResponseInterface::class)->getMock()).

Using MockResponse allows simulating chunked responses and timeouts:

$body = function () {
    yield 'hello';
    yield ''; // the empty string is turned into a timeout so that they are easy to test
    yield 'world';
};
$mockResponse = new MockResponse($body());

Last but not least, the implementation simulates the full lifecycle of a properly behaving HttpClientInterface contracts implementation: error handling, progress function, etc. This is "proved" by MockHttpClientTest, who implements and passes the reference test suite in HttpClientTestCase.

@nicolas-grekas nicolas-grekas added this to the next milestone Mar 19, 2019

@nicolas-grekas nicolas-grekas force-pushed the nicolas-grekas:feature/mock-client branch from 9a8f9a3 to 07bc27b Mar 19, 2019

@fabpot

fabpot approved these changes Mar 19, 2019

@nicolas-grekas nicolas-grekas force-pushed the nicolas-grekas:feature/mock-client branch 2 times, most recently from 8a7b0fc to 3a16803 Mar 19, 2019

@Nyholm
Copy link
Member

left a comment

I did a quick review. It looks alright, but I have not tested it yet.

@weaverryan
Copy link
Member

left a comment

Also haven't tested it, but the user experience looks wonderful!

@nicolas-grekas nicolas-grekas force-pushed the nicolas-grekas:feature/mock-client branch from 3a16803 to 8fd7584 Mar 19, 2019

@fabpot

This comment has been minimized.

Copy link
Member

commented Mar 19, 2019

Thank you @nicolas-grekas.

@fabpot fabpot merged commit 8fd7584 into symfony:master Mar 19, 2019

1 of 3 checks passed

continuous-integration/appveyor/pr Waiting for AppVeyor build to complete
Details
continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
fabbot.io Your code looks good.
Details

fabpot added a commit that referenced this pull request Mar 19, 2019

feature #30604 [HttpClient] add MockHttpClient (nicolas-grekas)
This PR was merged into the 4.3-dev branch.

Discussion
----------

[HttpClient] add MockHttpClient

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

This PR introduces `MockHttpClient` and `MockResponse`, to be used for testing classes that need an HTTP client without making actual HTTP requests.

`MockHttpClient` is configured via its constructor: you provide it either with an iterable or a callable, and these will be used to provide responses as the consumer requests them.

Example:
```php
$responses = [
    new MockResponse($body1, $info1),
    new MockResponse($body2, $info2),
];

$client = new MockHttpClient($responses);
$response1 = $client->request(...); // created from $responses[0]
$response2 = $client->request(...); // created from $responses[1]
```

Or alternatively:
```php
$callback = function ($method, $url, $options) {
    return new MockResponse(...);
};

$client = new MockHttpClient($callback);
$response = $client->request(...); // calls $callback internal
```

The responses provided to the client don't have to be instances of `MockResponse` - any `ResponseInterface` works (e.g. `$this->getMockBuilder(ResponseInterface::class)->getMock()`).

Using `MockResponse` allows simulating chunked responses and timeouts:
```php
$body = function () {
    yield 'hello';
    yield ''; // the empty string is turned into a timeout so that they are easy to test
    yield 'world';
};
$mockResponse = new Mockresponse($body);
```

Last but not least, the implementation simulates the full lifecycle of a properly behaving `HttpClientInterface` contracts implementation: error handling, progress function, etc. This is "proved" by `MockHttpClientTest`, who implements and passes the reference test suite in `HttpClientTestCase`.

Commits
-------

8fd7584 [HttpClient] add MockHttpClient

@nicolas-grekas nicolas-grekas deleted the nicolas-grekas:feature/mock-client branch Mar 19, 2019

@nicolas-grekas nicolas-grekas modified the milestones: next, 4.3 Apr 30, 2019

@fabpot fabpot referenced this pull request May 9, 2019

Merged

Release v4.3.0-BETA1 #31435

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.