Expectations

Expectations are the main way for you to define what you want Guzzler to search for through your Guzzle client's history. They are used in two separate ways:

  • To define the number of times you expect a match to be made before you test your code.
  • To assert what Guzzler should search for in your client's history after your code is run.

expects(InvokedRecorder $times, $message = null)

To mimic the chainable syntax of PHPUnit mock objects, you can create expectations with the expects() method and PHPUnit’s own InvokedRecorders. These are methods like $this->once(), $this->lessThan($int), $this->never(), and so on. You may also pass an optional message to be used on errors as the second argument.

public function testExample()
{
    $expectation = $this->guzzler->expects($this->once());
}

All methods on expectations are chainable and can lead directly into the next method. $expectation->oneMethod()->anotherMethod()->stillAnother();

Available Methods

asynchronous()

This method can be used to specify that the request should have been made with an asynchronous call; for example, $client->postAsync() instead of $client->post().

$this->guzzler->expects($this->once())
    ->asynchronous();

endpoint(string $uri, string $verb), {verb}(string $uri)

To specify the endpoint and method used for an expectation, use the endpoint() method or any of the convenience endpoint verb methods.

$this->guzzler->expects($this->once())
    ->endpoint("/some-url", "GET");

The following convenience verb methods are available to shorten your code. get, post, put, delete, patch, and options.

$this->guzzler->expects($this->any())
    ->get("/a-url-for-getting");

synchronous()

This method can be used to specify that the request should have been made with a synchronous call; for example, $client->get() instead of $client->getAsync().

$this->guzzler->expects($this->once())
    ->synchronous();

withBody(string $body, bool $exclusive = false)

You can expect a certain body on a request by passing a $body string to the withBody() method.

$this->guzzler->expects($this->once())
    ->withBody("some body string");

By default, this method simply checks that the specified body exists somewhere in the request body but more text may exist. By passing a boolean true as the second argument, the method will determine if the body equals the request.

withCallback(Closure $callback, string $message = null)

You can pass an anonymous method to do on-the-fly logic to determine if a history item fits your concerns. Your closure should expect a Guzzle history array, and return a boolean. A Guzzle history item is an array with the following structure:

// Guzzle history item structure
[
    "request"  => GuzzleHttp\Psr7\Request   object
    "response" => GuzzleHttp\Psr7\Response  object,
    "options"  => array,
    "errors"   => array
]
$this->guzzler->expects($this->once())
    ->withCallback(function ($history) {
        return isset($history['options']['cookies']);
    });

TIP

By default, the error message for a callback is simply "Custom callback: \Closure". It's recommended you pass your own message as the second argument to make a more descriptive failure.

withFile(string $fieldName, File $file)

You can make a set of expectations about a specific file that is included in a request. To do so, specify the field that the file should be under, and include an instance of the BlastCloud\Guzzler\Helpers\File class. The File class allows you to specify the following attributes of a file that is uploaded via a multipart form:

Attribute Description
contents The raw data of a given file.
contentType The mime type of the file. In HTTP requests, this becomes the Content-Type attribute.
filename If you choose to name the file something other than its actual file name.
headers Multipart forms allow headers on individual Content-Dispositions. The same checks as withHeaders are used here.

Example

There are several ways you can build out the attributes on a File object.

use BlastCloud\Guzzler\Helpers\File;

// Specify attributes on instantiation.
$file = new File($contents = null, string $filename = null, string $contentType = null, array $headers = null);

// Pass an associative array to a factory.
$file = File::create([
    'filename' => 'avatar.jpg',
    'contentType' => 'image/jpeg',
    'contents' => fopen('/path/to/file.jpg', 'r')
]);

// Set each attribute individually.
$file = new File();
$file->contents = fopen(__DIR__ . '/path/to/file.jpg', 'r');
$file->filename = 'avatar.jpg';

$this->guzzler->expects($this->once())
    ->withFile('avatar', $file);

The File class can accept contents in two different ways:

  1. The string contents are given directly.
  2. A resource, such as fopen(), is given.

Be Aware

Because the file given resolves down to an in-memory comparison, it's a good idea to only use reasonably small files during testing.

withFiles(array $files, bool $exclusive = false)

As a shorthand for passing multiple withFile() calls, you can provide an associative array of field names with BlastCloud\Guzzler\Helpers\File instances as the values.

$this->guzzler->expects($this->once())
    ->withFiles([
        'first' => File::create(['contents' => fopen('/path/to/file.png', 'r')]),
        'second' => File::create(['contents' => 'some text that would be in the second file']),
        // ...
    ]);

By default, this method simply checks that the specified files exist somewhere in the request, but more may exist. By passing a boolean true as the second argument, the method will instead cause a failure if additional files are found in the request.

withForm(array $formFields, bool $exclusive = false)

You can expect a specific set of form fields in the body of a post. This method works with both URL encoded and multipart forms.

$this->guzzler->expects($this->once())
    ->withForm([
        'first-name' => 'John',
        'last-name' => 'Snow'
    ]);

By default, this method simply checks that all specified fields and values exist in the request body, but more may exist. By passing a boolean true as the second argument, the method will instead cause a failure if additional fields are found.

withFormField(string $key, $value)

You can expect a specific form field in the body of a post. This method works with both URL encoded and multipart forms.

$this->guzzler->expects($this->once())
    ->withFormField('first-name', 'John')
    ->withFormField('house-name', 'Snow');

withHeader(string $key, string|array $value)

If you would like to expect a certain header to be on a request, you can provide the header and it’s value.

$this->guzzler->expects($this->once())
    ->withHeader("Authorization", "some-access-token");

Headers can also be an array of values.

$this->guzzler->expects($this->once())
    ->withHeader("Accept-Encoding", ["gzip", "deflate"]);

withHeaders(array $headers)

As a shorthand for multiple withHeader() calls, you can pass an array of header keys and values.

$this->guzzler->expects($this->once())
    ->withHeaders([
        "Accept-Encoding" => ["gzip", "deflate"],
        "Accept" => "application/json"
    ]);

withJson(array $json, bool $exclusive = false)

You can expect a certain JSON body on a request by passing an array of data to the withJson() method.

$this->guzzler->expects($this->once())
    ->withJson(['first' => 'value', 'second' => 'another']);

Be Aware

This method tests that the passed array exists on the request by first recursively sorting all keys and values in both the request body and the $json argument and then making a string comparison.

This means the following scenarios occur:

// Request body
[
    'first' => [
        'a value',
        'another value'
    ],
    'second' => 'second value'
]

// This expectation will pass. Remember, the request body and the
// argument are both recursively sorted before comparison.
$this->guzzler->expects($this->once())
    ->withJson(['another value', 'a value']);

// This expectation will fail
$this->guzzler->expects($this->once())
    ->withJson(['first' => ['another value']]);
    
// This expectation will pass
$this->guzzler->expects($this->once())
    ->withJson(['second' => 'second value']);

By default, this method checks only that the passed array of values exists somewhere in the request body, but more text may exist. A boolean true can be passed as the second argument to instead cause a failure if the body does not equal the json specified.

withOption(string $name, string $value)

You can expect a certain Client option by passing a name and value to this method.

$this->guzzler->expects($this->once())
    ->withOption('stream', true);

withOptions(array $options)

As a shorthand for multiple withOption() calls, you can pass an array of option keys and values.

$this->guzzler->expects($this->once())
    ->withOptions([
        'stream' => true,
        'allow_redirects' => false
    ]);

withProtocol($protocol)

You can expect a certain HTTP protocol (1.0, 1.1, 2.0) using the withProtocol() method.

$this->guzzler->expects($this->once())
    ->withProtocol(2.0);

withQuery(array $query, $exclusive = false)

You can expect a set of query parameters to appear in the URL of the request by passing an array of key/value pairs to match in the URL. The order of query parameters is not considered.

// Example URL: http://example.com/api/v2/customers?from=15&to=25&format=xml

$this->guzzler->expects($this->once())
    ->withQuery([
        'to' => 25,
        'from' => 15
    ]);

By default, this method only checks that the specified parameters exist somewhere in the request URL, but more may exist. A boolean true can be passed as the second argument to instead cause a failure if additional parameters are found.

// Example URL: http://example.com/api/v2/customers?from=15&to=25&format=xml

// With the second argument, the 'format' parameter causes the expectation to fail.
$this->guzzler->expects($this->once())
    ->withQuery([
        'to' => 25,
        'from' => 15
    ], true);

withQueryKey(string $key)

You can specify just the key for a query item, if you either don't care about the value or there is none. For example, ElasticSearch sometimes has a query key but no following value.

// Example URL: http://some-elasticsearch-url?_delete_by_query

$this->guzzler->expects($this->once())
    ->withQueryKey('_delete_by_query');

Be Aware

If you have a query variable that should have no value, like the example shown above, you must specify it in the raw request URL string. Adding it to a query variable in the request will force it to become a 0 indexed value, rather than a key.

// Doing this
$this->client->get('/url', [
    'query' => [
        'first' => 'value',
        'second'
    ]
]);

// Will cause Guzzle to make a query like this
// http://url?first=value&0=second

// This will work as intended though.
$this->client->get('/url?first=value&second');

withQueryKeys(array $keys)

You can specify just the keys you want to appear in the query, but not specifically check any values they may have.

$this->guzzler->expects($this->once())
    ->withQueryKeys(['first', 'second']);

withoutQuery()

If you'd like to ensure no query string is provided in the request at all, this method can be used.

$this->guzzler->expects($this->once())
    ->withoutQuery();
Last Updated: 1/10/2020, 7:16:46 AM