-
Notifications
You must be signed in to change notification settings - Fork 4
CurlInterface
The goal of the CurlInterface
is to provide a wrapper for the cURL extension’s calls that can easily be stubbed. At the same time it should not require much work to replace existing calls that go straight to PHP (without intermediate classes) with the ones provided here. Hence, the interface does not provide any convenience function but is a direct mapping of PHP’s cURL functions. This repository contains two implementations of the interface:
Curl
CurlStub
All Curl
does, is delegate method calls further to the cURL extension. No more and no less. This means, if you want to move from calling the cURL functions directly to using the interface, all you have to do is instantiate the Curl
class and call all functions on this object. For example, if you had this before:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$curlError = curl_error($ch);
$curlInfo = curl_getinfo($ch);
curl_close($ch);
You can now simply do this:
$curl = new SAI_Curl();
$ch = $curl->curl_init($url);
$curl->curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = $curl->curl_exec($ch);
$curlError = $curl->curl_error($ch);
$curlInfo = $curl->curl_getinfo($ch);
$curl->curl_close($ch);
NOTE: you can also use all multi-lib cURL functions on this class.
Of course, to make full use of this, $curl
should be treated as anything that implements CurlInterface
and be given to the class using it from the outside. This approach allows to replace Curl
by CurlStub
for testing purposes.
NOTE: As of version 0.1, CurlStub
does not support multi-lib cURL functions yet!
Now concerning the real purpose of this interface. When you want to unit-test a class that uses cURL it is usually very annoying that the class has to send out actual HTTP requests to get its work done. By having your unit test hand the class an instance of CurlStub
instead of Curl
you can avoid this.
CurlStub
allows you to define certain responses, error codes and cURL-info data for different request options. These will then be delivered to the Class Under Test (CUT) as if cURL had actually requested them from a remote server.
Here is an example test, to show you how it works. Let’s say we have a class ClassUnderTest
, that uses cURL to retrieve data from http://www.myserver.com
and simply returns that data.
public function testGetData()
{
$curl = new SAI_CurlStub();
// Set up the CurlStub
$requiredOptions = array(
CURLOPT_URL => 'http://www.myserver.com'
);
$curl->setResponse('example result', $requiredOptions);
$cut = new ClassUnderTest($curl);
$this->assertEquals('example result', $cut->getData());
}
In this case, the test would pass if our ClassUnderTest
would send the request to ‘http://www.myserver.com’ and simply return the response.
The CurlStub
comes with a bunch of other features, which are outlined shortly in this section. For more details on their usage, check out the tests in tests/SAI_CurlStubTest.php
. They give a good overview of what is possible.
In addition to setResponse()
there are setErrorCode()
and setInfo()
which work exactly the same. setInfo()
can define any subset of the options given in the Parameters section of this page. They are given to setInfo()
as an array with the CURLINFO_*
constants as the keys and their values as strings. For instance:
$errorCode = CURLE_OK;
$info = array(
CURLINFO_HTTP_CODE => '200',
CURLINFO_TOTAL_TIME => '2'
);
$requiredOptions = array(
CURLOPT_URL => 'http://www.myserver.com'
);
$curl->setErrorCode($errorCode, $requiredOptions);
$curl->setInfo($info, $requiredOptions);
All info options that have not been set up will be returned as empty strings.
By using the $requiredOptions
you have quite a lot of flexibility in setting up different responses (or error codes, or cURL-info for that matter).
First of all, you can omit the parameter. This will make the response a default. So if none of your other required option sets match, this response will be returned. For example, you could set up an empty response and an error code CURLE_COULDNT_RESOLVE_HOST
.
Secondly, you can provide multiple responses for different values of the same option. For example:
$response1 = 'google page found';
$requiredOptions1 = array(
CURLOPT_URL => 'http://www.google.com'
);
$response2 = 'bing page found';
$requiredOptions2 = array(
CURLOPT_URL => 'http://www.bing.com'
);
$curl->setResponse($response1, $requiredOptions1);
$curl->setResponse($response2, $requiredOptions2);
Thirdly, (as you might have guessed because $requiredOptions
is an array) you can specify a combination of multiple options. In fact, you can make your response dependent on any option (and any combination of them). Any option that you do not set will be treated as a wildcard. In terms of priorities, more specific option sets go first. Here is an example to illustrate this:
$response1 = 'default page found';
$requiredOptions1 = array(
CURLOPT_URL => 'http://www.myserver.com'
);
$response2 = 'page for chrome found';
$requiredOptions2 = array(
CURLOPT_URL => 'http://www.myserver.com',
CURLOPT_USERAGENT => 'Chrome/22.0.1207.1'
);
$response3 = 'page for safari found';
$requiredOptions3 = array(
CURLOPT_URL => 'http://www.myserver.com',
CURLOPT_USERAGENT => 'Safari/537.1'
);
$curl->setResponse($response1, $requiredOptions1);
$curl->setResponse($response2, $requiredOptions2);
$curl->setResponse($response3, $requiredOptions3);
Now responses 2 and 3 have more specific requirements, so if these can be fulfilled, they will be returned. If a request is sent to the correct URL, but without one of the specified user agents, the CurlStub
will still return the default response (1).
NOTE: Within CurlStub
options are exclusively considered for matching responses, error codes and cURL-info. However, there is one exception to this rule: CURLOPT_RETURNTRANSFER
is treated the same way as in PHP’s curl_exec()
. If the option is set, curl_exec()
will return the response. Otherwise, it will echo
the reponse and return a boolean flag, denoting success or failure. In theory, this cURL option can also be used for setting up different responses, but it is not very useful, because the option would not affect the response if cURL itself was used.
NOTE: “Specificity” of responses is only determined by the number of options you set. This means, if you set up one response for the option CURLOPT_URL
and one for CURLOPT_USERAGENT
and one for CURLOPT_REFERER
, they will have the same priority for CurlStub
. However, more than one of these could match a certain request – in this case an arbitrary response of the matching ones will be returned.