I want to mock a response to the Guzzle request:
$response = new Response(200, ['X-Foo' => 'Bar']);
//how do I set content of $response to--> "some mocked content"
$client = Mockery::mock('GuzzleHttp\Client');
$client->shouldReceive('get')->once()->andReturn($response);
I noticed I need to add as third parameter the interface:
GuzzleHttp\Stream\StreamInterface
but there are so many implementations of it, and I want to return a simple string. Any ideas?
Edit: now I use this:
$response = new Response(200, [], GuzzleHttp\Stream\Stream::factory('bad xml here'));
but when I check this:
$response->getBody()->getContents()
I get an empty string. Why is this?
Edit 2: this happened to me only when I used xdebug, when it runs normally it works great!
We'll just keep doing this. The previous answer is for Guzzle 5, this is for Guzzle 6:
use GuzzleHttp\Psr7;
$stream = Psr7\stream_for('{"data" : "test"}');
$response = new Response(200, ['Content-Type' => 'application/json'], $stream);
The previous answer is for Guzzle 3. Guzzle 5 uses the following:
<?php
$body = GuzzleHttp\Stream\Stream::factory('some mocked content');
$response = new Response(200, ['X-Foo' => 'Bar'], $body);
Using #tomvo answer and the comment from #Tim - this is what I did for testing Guzzle 6 inside my Laravel app:
use GuzzleHttp\Psr7\Response;
$string = json_encode(['data' => 'test']);
$response = new Response(200, ['Content-Type' => 'application/json'], $string);
$guzzle = Mockery::mock(GuzzleHttp\Client::class);
$guzzle->shouldReceive('get')->once()->andReturn($response);
Guzzle\Http\Message\Response allows you to specify the third parameter as a string.
$body = '<html><body>Hello world!</body></html>';
$response = new Response(200, ['X-Foo' => 'Bar'], $body);
If you'd prefer a solution that implements Guzzle\Stream\StreamInterface, then I recommend using Guzzle\Http\EntityBody for the most straightforward implementation:
$body = Guzzle\Http\EntityBody::fromString('<html><body>Hello world!</body></html>');
$response = new Response(200, ['X-Foo' => 'Bar'], $body);
For Guzzle 7, you can use the GuzzleHttp\Psr7\Utils::streamFor() method as follows:
$data = json_encode(['X-Foo' => 'Bar']);
$stream = Utils::streamFor($data);
And then you can pass the $stream object to the andReturn method of the mocked client.
Related
i'm using PHP with Guzzle.
I have this code:
$client = new Client();
$request = new \GuzzleHttp\Psr7\Request('POST', 'http://localhost/async-post/tester.php',[
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'form_params' => [
'action' => 'TestFunction'
],
]);
$promise = $client->sendAsync($request)->then(function ($response) {
echo 'I completed! ' . $response->getBody();
});
$promise->wait();
For some reason Guzzle Doesn't send the POST Parameters.
Any suggestion?
Thanks :)
I see 2 things.
The parameters have to go as string (json_encode)
And you were also including them as part of the HEADER, not the BODY.
Then i add a function to handle the response as ResponseInterface
$client = new Client();
$request = new Request('POST', 'https://google.com', ['Content-Type' => 'application/x-www-form-urlencoded'], json_encode(['form_params' => ['s' => 'abc',] ]));
/** #var Promise\PromiseInterface $response */
$response = $client->sendAsync($request);
$response->then(
function (ResponseInterface $res) {
echo $res->getStatusCode() . "\n";
},
function (RequestException $e) {
echo $e->getMessage() . "\n";
echo $e->getRequest()->getMethod();
}
);
$response->wait();
In this test Google responds with a
Client error: POST https://google.com resulted in a 405 Method Not Allowed
But is ok. Google doesn't accepts request like this.
Guzzle isn't truely asynchronous. It's more of multi-threading. That is why you have the wait() line to prevent the your current PHP script from closing until all multiple spun threads finish. If you remove the wait() line, the PHP process spun by the script ends immediately with all it's threads and your request is never sent.
Ergo, you need Guzzle (and Curl) for multi-processing(concurrent) I/O and not for asynchronous I/O. In your case, you are processing one request and Guzzle promises are simply an overkill.
To send a request with Guzzle, simply do this:
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
$client = new Client();
$header = ['Content-Type' => 'application/x-www-form-urlencoded'];
$body = json_encode(['id' => '2', 'name' => 'dan']);
$request = new Request('POST', 'http://localhost/async-post/tester.php', $header, $body);
$response = $client->send($request);
Also, it seems you are using the form action attribute rather than the actual form data in form-params.
I'm posting this answer because I tried to achieve something really asynchronous with php - Schedule I/O processing as a background task, continue processing script and serve the page; I/O continues in background and completes without disrupting the client. Laravel Queues was the best thing I could find.
I have a class with the following function :
public function get(string $uri) : stdClass
{
$this->client = new Client;
$response = $this->client->request(
'GET',
$uri,
$this->headers
);
return json_decode($response->getBody());
}
How can I mock the request method from PHPUnit? I tried different ways but it always tries to connect to the uri specified.
I tried with :
$clientMock = $this->getMockBuilder('GuzzleHttp\Client')
->setMethods('request')
->getMock();
$clientMock->expects($this->once())
->method('request')
->willReturn('{}');
But this didn't work. What can I do? I just need to mock the response to be empty.
Thanks
PD : Client comes from (use GuzzleHttp\Client)
I think as suggested is better to use http://docs.guzzlephp.org/en/stable/testing.html#mock-handler
as it looks like the most elegant way to do it properly.
Thank you all
The mocked Response doesn't need to be anything in particular, your code just expects it to be an object with a getBody method. So you can just use a stdClass, with a getBody method which returns some json_encoded object. Something like:
$jsonObject = json_encode(['foo']);
$uri = 'path/to/foo/bar/';
$mockResponse = $this->getMockBuilder(\stdClass::class)->getMock();
$mockResponse->method('getBody')->willReturn($jsonObject);
$clientMock = $this->getMockBuilder('GuzzleHttp\Client')->getMock();
$clientMock->expects($this->once())
->method('request')
->with(
'GET',
$uri,
$this->anything()
)
->willReturn($mockResponse);
$result = $yourClass->get($uri);
$expected = json_decode($jsonObject);
$this->assertSame($expected, $result);
I prefer this way to mock a Client in PHP. In this example I am using Guzzle Client.
Clone the code or install it via composer
$ composer require doppiogancio/mocked-client
And then...
$builder = new HandlerStackBuilder();
// Add a route with a response via callback
$builder->addRoute(
'GET', '/country/IT', static function (ServerRequestInterface $request): Response {
return new Response(200, [], '{"id":"+39","code":"IT","name":"Italy"}');
}
);
// Add a route with a response in a text file
$builder->addRouteWithFile('GET', '/country/IT/json', __DIR__ . '/fixtures/country.json');
// Add a route with a response in a string
$builder->addRouteWithFile('GET', '{"id":"+39","code":"IT","name":"Italy"}');
// Add a route mocking directly the response
$builder->addRouteWithResponse('GET', '/admin/dashboard', new Response(401));
$client = new Client(['handler' => $builder->build()]);
Once you have mocked the client you can use it like this:
$response = $client->request('GET', '/country/DE/json');
$body = (string) $response->getBody();
$country = json_decode($body, true);
print_r($country);
// will return
Array
(
[id] => +49
[code] => DE
[name] => Germany
)
In addition to the current answer about using MockHandler, it's possible to process the request so that you can validate the calls.
The following example passes a callable which just tests the request method and throws an exception if not POST, if that is OK it returns the response. The principle can be expanded to test other details about the request...
$mock = new MockHandler([
function ($request) {
$this->assertEquals('POST', $request->getMethod());
return new Response(
200,
[],
json_encode([ "access_token" => '1234e' ])
);
},
new Response(
200,
[],
json_encode([ "details" =>
[
[
"orderID" => 229783,
],
[
"orderID" => 416270,
],
],
])
),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
So the first call to the client has the test included, the second call just returns a response.
Just noticed that any time you use a callable to process the request, you MUST return a Response object if you expect the process to continue.
I have a method using gullzehttp and would like to change it to the pool plus the pool implements the Request method
<?php
use GuzzleHttp\Client;
$params = ['password' => '123456'];
$header = ['Accept' => 'application/xml'];
$options = ['query' => $params, 'headers' => $header];
$response = $client->request('GET', 'http://httpbin.org/get', $options);
I need to change to the Request method, but I could not find in the documentation how to send querystring variables in the Request
<?php
use GuzzleHttp\Psr7\Request;
$request = new Request('GET', 'http://httpbin.org/get', $options);
You need to add the query as a string to the URI.
For that you can use http_build_query or a guzzle helper function to convert a parameter array to an encoded query string:
$uri = new Uri('http://httpbin.org/get');
$request = new Request('GET', $uri->withQuery(GuzzleHttp\Psr7\build_query($params)));
// OR
$request = new Request('GET', $uri->withQuery(http_build_query($params)));
I also had trouble figuring out how to properly place the new Request() parameters. but structuring it the way i did below using php http_build_query to convert my arrays to query params and then appended it to the url before sending fixed it.
try {
// Build a client
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'https://pro-api.coinmarketcap.com',
// You can set any number of default request options.
// 'timeout' => 2.0,
]);
// Prepare a request
$url = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest';
$headers = [
'Accepts' => 'application/json',
'X-CMC_PRO_API_KEY' => '05-88df-6f98ba'
];
$params = [
'id' => '1'
];
$request = new Request('GET', $url.'?'.http_build_query($params), $headers);
// Send a request
$response = $client->send($request);
// Receive a response
dd($response->getBody()->getContents());
return $response->getBody()->getContents();
} catch (\Throwable $th) {
dd('did not work', $th);
return false;
}
With Guzzle (version 3), I'd like to specify the body of a POST request in "raw" mode. I'm currently trying this:
$guzzleRequest = $client->createRequest(
'POST',
$uri,
null,
'un=one&deux=two'
);
But it kind of doesn't work. If I dump my $guzzleRequest I can see that postFields->data is empty. Using $guzzleRequest->setBody() afterwards doesn't help.
However if I specify the body as ['un'=>'one', 'deux'=>'two'], it works as expected.
How can I specify the body of the request as 'un=one&deux=two'?
First I would highly recommend that you upgrade to Guzzle 6 as Guzzle 3 is deprecated and EOL.
It has been a long time since I used Guzzle 3 but I do believe you want the following:
$request = $client->post(
$uri,
$header = [],
$params = [
'un' => 'one',
'deux' => 'two',
]);
$response = $request->send();
Guzzle will automatically set the Content-Type header.
More information is available with the Post Request Documentation.
In response to your comment:
$request = $client->post(
$uri,
$headers = ['Content-Type' => 'application/x-www-form-urlencoded'],
EntityBody::fromString($urlencodedstring)
)
For this, reference: EntityBody Source and RequestFactory::create()
I'm searching to retrieve the request total time in Guzzle 6, just after a simple GET request :
$client = new GuzzleHttp\Client();
$response = client->get('http://www.google.com/');
But can't find anything in the docs about that. Any idea ?
Thanks a lot.
In Guzzle 6.1.0 You can use the 'on_stats' request option to get transfer time etc.
More information can be found at Request Options - on_stats
https://github.com/guzzle/guzzle/releases/tag/6.1.0
You can use setter and getter.
private $totaltime = 0;
public function getTotaltime(){
return $this->totaltime;
}
public function setTotaltime($time){
$this->totaltime = $time;
}
$reqtime= new self();
$response = $client->post($endpointLogin, [
'json' => $payload,
'headers' => $this->header,
'on_stats' => function (TransferStats $stats) use ($reqtime) {
$stats->getTransferTime();
//** set it here **//
$reqtime->setTotaltime($stats->getTransferTime());
}
]);
dd($reqtime->getTotaltime());
An specific example based on the #Michael post.
$client = new GuzzleHttp\Client();
$response = $client->get('http://www.google.com/', [
'on_stats' => function (\GuzzleHttp\TransferStats $stats) {
echo $stats->getEffectiveUri() . ' : ' . $stats->getTransferTime();
}
]);
$client = new GuzzleHttp\Client();
$one = microtime(1);
$response = $client->get('http://www.google.com/');
$two = microtime(1);
echo 'Total Request time: '. ( $two - $one );
I had a similar problem although it's still Guzzle 5.3.
See Guzzle 5.3 - Get request duration for asynchronous requests
Maybe listening to an event in Guzzle6 and retrieving the TransferInfo will do the trick for you too.
This works for synchronous and asynchronous requests alike.