diff options
Diffstat (limited to 'vendor/guzzle/guzzle/docs/testing/unit-testing.rst')
-rw-r--r-- | vendor/guzzle/guzzle/docs/testing/unit-testing.rst | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/vendor/guzzle/guzzle/docs/testing/unit-testing.rst b/vendor/guzzle/guzzle/docs/testing/unit-testing.rst new file mode 100644 index 0000000..f4297af --- /dev/null +++ b/vendor/guzzle/guzzle/docs/testing/unit-testing.rst @@ -0,0 +1,201 @@ +=========================== +Unit Testing Guzzle clients +=========================== + +Guzzle provides several tools that will enable you to easily unit test your web service clients. + +* PHPUnit integration +* Mock responses +* node.js web server for integration testing + +PHPUnit integration +------------------- + +Guzzle is unit tested using `PHPUnit <http://www.phpunit.de/>`_. Your web service client's unit tests should extend +``Guzzle\Tests\GuzzleTestCase`` so that you can take advantage of some of the built in helpers. + +In order to unit test your client, a developer would need to copy phpunit.xml.dist to phpunit.xml and make any needed +modifications. As a best practice and security measure for you and your contributors, it is recommended to add an +ignore statement to your SCM so that phpunit.xml is ignored. + +Bootstrapping +~~~~~~~~~~~~~ + +Your web service client should have a tests/ folder that contains a bootstrap.php file. The bootstrap.php file +responsible for autoloading and configuring a ``Guzzle\Service\Builder\ServiceBuilder`` that is used throughout your +unit tests for loading a configured client. You can add custom parameters to your phpunit.xml file that expects users +to provide the path to their configuration data. + +.. code-block:: php + + Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Aws\Common\Aws::factory($_SERVER['CONFIG'])); + + Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Guzzle\Service\Builder\ServiceBuilder::factory(array( + 'test.unfuddle' => array( + 'class' => 'Guzzle.Unfuddle.UnfuddleClient', + 'params' => array( + 'username' => 'test_user', + 'password' => '****', + 'subdomain' => 'test' + ) + ) + ))); + +The above code registers a service builder that can be used throughout your unit tests. You would then be able to +retrieve an instantiated and configured Unfuddle client by calling ``$this->getServiceBuilder()->get('test.unfuddle)``. +The above code assumes that ``$_SERVER['CONFIG']`` contains the path to a file that stores service description +configuration. + +Unit testing remote APIs +------------------------ + +Mock responses +~~~~~~~~~~~~~~ + +One of the benefits of unit testing is the ability to quickly determine if there are errors in your code. If your +unit tests run slowly, then they become tedious and will likely be run less frequently. Guzzle's philosophy on unit +testing web service clients is that no network access should be required to run the unit tests. This means that +responses are served from mock responses or local servers. By adhering to this principle, tests will run much faster +and will not require an external resource to be available. The problem with this approach is that your mock responses +must first be gathered and then subsequently updated each time the remote API changes. + +Integration testing over the internet +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can perform integration testing with a web service over the internet by making calls directly to the service. If +the web service you are requesting uses a complex signing algorithm or some other specific implementation, then you +may want to include at least one actual network test that can be run specifically through the command line using +`PHPUnit group annotations <http://www.phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group>`_. + +@group internet annotation +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When creating tests that require an internet connection, it is recommended that you add ``@group internet`` annotations +to your unit tests to specify which tests require network connectivity. + +You can then `run PHPUnit tests <http://www.phpunit.de/manual/current/en/textui.html>`_ that exclude the @internet +group by running ``phpunit --exclude-group internet``. + +API credentials +^^^^^^^^^^^^^^^ + +If API credentials are required to run your integration tests, you must add ``<php>`` parameters to your +phpunit.xml.dist file and extract these parameters in your bootstrap.php file. + +.. code-block:: xml + + <?xml version="1.0" encoding="UTF-8"?> + <phpunit bootstrap="./tests/bootstrap.php" colors="true"> + <php> + <!-- Specify the path to a service configuration file --> + <server name="CONFIG" value="test_services.json" /> + <!-- Or, specify each require parameter individually --> + <server name="API_USER" value="change_me" /> + <server name="API_PASSWORD" value="****" /> + </php> + <testsuites> + <testsuite name="guzzle-service"> + <directory suffix="Test.php">./Tests</directory> + </testsuite> + </testsuites> + </phpunit> + +You can then extract the ``server`` variables in your bootstrap.php file by grabbing them from the ``$_SERVER`` +superglobal: ``$apiUser = $_SERVER['API_USER'];`` + +Further reading +^^^^^^^^^^^^^^^ + +A good discussion on the topic of testing remote APIs can be found in Sebastian Bergmann's +`Real-World Solutions for Developing High-Quality PHP Frameworks and Applications <http://www.amazon.com/dp/0470872497>`_. + +Queueing Mock responses +----------------------- + +Mock responses can be used to test if requests are being generated correctly and responses and handled correctly by +your client. Mock responses can be queued up for a client using the ``$this->setMockResponse($client, $path)`` method +of your test class. Pass the client you are adding mock responses to and a single path or array of paths to mock +response files relative to the ``/tests/mock/ folder``. This will queue one or more mock responses for your client by +creating a simple observer on the client. Mock response files must contain a full HTTP response message: + +.. code-block:: none + + HTTP/1.1 200 OK + Date: Wed, 25 Nov 2009 12:00:00 GMT + Connection: close + Server: AmazonS3 + Content-Type: application/xml + + <?xml version="1.0" encoding="UTF-8"?> + <LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">EU</LocationConstraint> + +After queuing mock responses for a client, you can get an array of the requests that were sent by the client that +were issued a mock response by calling ``$this->getMockedRequests()``. + +You can also use the ``Guzzle\Plugin\Mock\MockPlugin`` object directly with your clients. + +.. code-block:: php + + $plugin = new Guzzle\Plugin\Mock\MockPlugin(); + $plugin->addResponse(new Guzzle\Http\Message\Response(200)); + $client = new Guzzle\Http\Client(); + $client->addSubscriber($plugin); + + // The following request will get the mock response from the plugin in FIFO order + $request = $client->get('http://www.test.com/'); + $request->send(); + + // The MockPlugin maintains a list of requests that were mocked + $this->assertContainsOnly($request, $plugin->getReceivedRequests()); + +node.js web server for integration testing +------------------------------------------ + +Using mock responses is usually enough when testing a web service client. If your client needs to add custom cURL +options to requests, then you should use the node.js test web server to ensure that your HTTP request message is +being created correctly. + +Guzzle is based around PHP's libcurl bindings. cURL sometimes modifies an HTTP request message based on +``CURLOPT_*`` options. Headers that are added to your request by cURL will not be accounted for if you inject mock +responses into your tests. Additionally, some request entity bodies cannot be loaded by the client before transmitting +it to the sever (for example, when using a client as a sort of proxy and streaming content from a remote server). You +might also need to inspect the entity body of a ``multipart/form-data`` POST request. + +.. note:: + + You can skip all of the tests that require the node.js test web server by excluding the ``server`` group: + ``phpunit --exclude-group server`` + +Using the test server +~~~~~~~~~~~~~~~~~~~~~ + +The node.js test server receives requests and returns queued responses. The test server exposes a simple API that is +used to enqueue responses and inspect the requests that it has received. + +Retrieve the server object by calling ``$this->getServer()``. If the node.js server is not running, it will be +started as a forked process and an object that interfaces with the server will be returned. (note: stopping the +server is handled internally by Guzzle.) + +You can queue an HTTP response or an array of responses by calling ``$this->getServer()->enqueue()``: + +.. code-block:: php + + $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"); + +The above code queues a single 200 response with an empty body. Responses are queued using a FIFO order; this +response will be returned by the server when it receives the first request and then removed from the queue. If a +request is received by a server with no queued responses, an exception will be thrown in your unit test. + +You can inspect the requests that the server has retrieved by calling ``$this->getServer()->getReceivedRequests()``. +This method accepts an optional ``$hydrate`` parameter that specifies if you are retrieving an array of string HTTP +requests or an array of ``Guzzle\Http\RequestInterface`` subclassed objects. "Hydrating" the requests will allow +greater flexibility in your unit tests so that you can easily assert the state of the various parts of a request. + +You will need to modify the base_url of your web service client in order to use it against the test server. + +.. code-block:: php + + $client = $this->getServiceBuilder()->get('my_client'); + $client->setBaseUrl($this->getServer()->getUrl()); + +After running the above code, all calls made from the ``$client`` object will be sent to the test web server. |