amphp / http-client

An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.
https://amphp.org/http-client
MIT License
704 stars 66 forks source link

How to mock http requests #273

Closed suadhuskic closed 3 years ago

suadhuskic commented 4 years ago

Are there examples on how to mock out sending requests? I looked through the examples folder and website, but couldn't find anything

kelunik commented 4 years ago

I guess what you want is providing a fake response to any request? Which mocking framework do you use? Or do you intend to write a simple mock implementation yourself that fulfills your requirements?

suadhuskic commented 4 years ago

Yeah, i guess you can say that. We are using Mockery but i doubt that would work here? I haven't actually tried it.

Here is an example of a function that is proxying back specific exceptions when we get a 400 from an external API. I want to test that the correct exceptions are being thrown depending on the status code & response body:

    public function callSomeExternalApi(
        array $payload,
        ?CancellationToken $cancellationToken = null
    ): Promise {
        $url = self::BASE_URL;

        $request = new Request($url, 'POST', '');
        $request->setBody(http_build_query(payload));
        $request->addHeader('Content-Type', 'application/x-www-form-urlencoded');

        return call(function () use ($request, $cancellationToken) {
            $response = yield $this->httpClient->request($request, $cancellationToken);
            $body = yield $response->getBody()->buffer();

            $responseBody = json_decode($body, true);

            if ($response->getStatus() === Response::HTTP_OK) {
                return responseBody;
            } elseif ($response->getStatus() === Response::HTTP_BAD_REQUEST) {
                $errorCode = $responseBody['code'] ?? null;

                if ($errorCode === self::ERROR_CODE_1) {
                    throw new ERROR_CODE_1Exception();
                }

                if ($errorCode === self::ERROR_CODE_2) {
                    throw new ERROR_CODE_2Exception();
                }
                throw new BadRequestException('Failed to fetch external stuff..');
            } else {
                throw new ExternalServerError('There was a problem.');
            }
        });
    }

$this->httpClient is an instanceof Amp\Http\Client\HttpClient::class with a pre authorization header set, nothing else.

suadhuskic commented 4 years ago

Actually, let me try creating a ApplicationInterceptor and returning early

kelunik commented 4 years ago

You can either do that or mock DelegateHttpClient and then use new HttpClient($mock). It all depends on the level you'd like to mock.

kelunik commented 3 years ago

It seems like all questions have been answered. If not, please respond with further questions, the issue can always be re-opened. :+1: