PageRenderTime 32ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/api/vendor/guzzle/guzzle/docs/testing/unit-testing.rst

https://gitlab.com/x33n/respond
ReStructuredText | 201 lines | 147 code | 54 blank | 0 comment | 0 complexity | ca0ea059d266154df6148267650f6bc1 MD5 | raw file
  1. ===========================
  2. Unit Testing Guzzle clients
  3. ===========================
  4. Guzzle provides several tools that will enable you to easily unit test your web service clients.
  5. * PHPUnit integration
  6. * Mock responses
  7. * node.js web server for integration testing
  8. PHPUnit integration
  9. -------------------
  10. Guzzle is unit tested using `PHPUnit <http://www.phpunit.de/>`_. Your web service client's unit tests should extend
  11. ``Guzzle\Tests\GuzzleTestCase`` so that you can take advantage of some of the built in helpers.
  12. In order to unit test your client, a developer would need to copy phpunit.xml.dist to phpunit.xml and make any needed
  13. modifications. As a best practice and security measure for you and your contributors, it is recommended to add an
  14. ignore statement to your SCM so that phpunit.xml is ignored.
  15. Bootstrapping
  16. ~~~~~~~~~~~~~
  17. Your web service client should have a tests/ folder that contains a bootstrap.php file. The bootstrap.php file
  18. responsible for autoloading and configuring a ``Guzzle\Service\Builder\ServiceBuilder`` that is used throughout your
  19. unit tests for loading a configured client. You can add custom parameters to your phpunit.xml file that expects users
  20. to provide the path to their configuration data.
  21. .. code-block:: php
  22. Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Aws\Common\Aws::factory($_SERVER['CONFIG']));
  23. Guzzle\Tests\GuzzleTestCase::setServiceBuilder(Guzzle\Service\Builder\ServiceBuilder::factory(array(
  24. 'test.unfuddle' => array(
  25. 'class' => 'Guzzle.Unfuddle.UnfuddleClient',
  26. 'params' => array(
  27. 'username' => 'test_user',
  28. 'password' => '****',
  29. 'subdomain' => 'test'
  30. )
  31. )
  32. )));
  33. The above code registers a service builder that can be used throughout your unit tests. You would then be able to
  34. retrieve an instantiated and configured Unfuddle client by calling ``$this->getServiceBuilder()->get('test.unfuddle)``.
  35. The above code assumes that ``$_SERVER['CONFIG']`` contains the path to a file that stores service description
  36. configuration.
  37. Unit testing remote APIs
  38. ------------------------
  39. Mock responses
  40. ~~~~~~~~~~~~~~
  41. One of the benefits of unit testing is the ability to quickly determine if there are errors in your code. If your
  42. unit tests run slowly, then they become tedious and will likely be run less frequently. Guzzle's philosophy on unit
  43. testing web service clients is that no network access should be required to run the unit tests. This means that
  44. responses are served from mock responses or local servers. By adhering to this principle, tests will run much faster
  45. and will not require an external resource to be available. The problem with this approach is that your mock responses
  46. must first be gathered and then subsequently updated each time the remote API changes.
  47. Integration testing over the internet
  48. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  49. You can perform integration testing with a web service over the internet by making calls directly to the service. If
  50. the web service you are requesting uses a complex signing algorithm or some other specific implementation, then you
  51. may want to include at least one actual network test that can be run specifically through the command line using
  52. `PHPUnit group annotations <http://www.phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group>`_.
  53. @group internet annotation
  54. ^^^^^^^^^^^^^^^^^^^^^^^^^^
  55. When creating tests that require an internet connection, it is recommended that you add ``@group internet`` annotations
  56. to your unit tests to specify which tests require network connectivity.
  57. You can then `run PHPUnit tests <http://www.phpunit.de/manual/current/en/textui.html>`_ that exclude the @internet
  58. group by running ``phpunit --exclude-group internet``.
  59. API credentials
  60. ^^^^^^^^^^^^^^^
  61. If API credentials are required to run your integration tests, you must add ``<php>`` parameters to your
  62. phpunit.xml.dist file and extract these parameters in your bootstrap.php file.
  63. .. code-block:: xml
  64. <?xml version="1.0" encoding="UTF-8"?>
  65. <phpunit bootstrap="./tests/bootstrap.php" colors="true">
  66. <php>
  67. <!-- Specify the path to a service configuration file -->
  68. <server name="CONFIG" value="test_services.json" />
  69. <!-- Or, specify each require parameter individually -->
  70. <server name="API_USER" value="change_me" />
  71. <server name="API_PASSWORD" value="****" />
  72. </php>
  73. <testsuites>
  74. <testsuite name="guzzle-service">
  75. <directory suffix="Test.php">./Tests</directory>
  76. </testsuite>
  77. </testsuites>
  78. </phpunit>
  79. You can then extract the ``server`` variables in your bootstrap.php file by grabbing them from the ``$_SERVER``
  80. superglobal: ``$apiUser = $_SERVER['API_USER'];``
  81. Further reading
  82. ^^^^^^^^^^^^^^^
  83. A good discussion on the topic of testing remote APIs can be found in Sebastian Bergmann's
  84. `Real-World Solutions for Developing High-Quality PHP Frameworks and Applications <http://www.amazon.com/dp/0470872497>`_.
  85. Queueing Mock responses
  86. -----------------------
  87. Mock responses can be used to test if requests are being generated correctly and responses and handled correctly by
  88. your client. Mock responses can be queued up for a client using the ``$this->setMockResponse($client, $path)`` method
  89. of your test class. Pass the client you are adding mock responses to and a single path or array of paths to mock
  90. response files relative to the ``/tests/mock/ folder``. This will queue one or more mock responses for your client by
  91. creating a simple observer on the client. Mock response files must contain a full HTTP response message:
  92. .. code-block:: none
  93. HTTP/1.1 200 OK
  94. Date: Wed, 25 Nov 2009 12:00:00 GMT
  95. Connection: close
  96. Server: AmazonS3
  97. Content-Type: application/xml
  98. <?xml version="1.0" encoding="UTF-8"?>
  99. <LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">EU</LocationConstraint>
  100. After queuing mock responses for a client, you can get an array of the requests that were sent by the client that
  101. were issued a mock response by calling ``$this->getMockedRequests()``.
  102. You can also use the ``Guzzle\Plugin\Mock\MockPlugin`` object directly with your clients.
  103. .. code-block:: php
  104. $plugin = new Guzzle\Plugin\Mock\MockPlugin();
  105. $plugin->addResponse(new Guzzle\Http\Message\Response(200));
  106. $client = new Guzzle\Http\Client();
  107. $client->addSubscriber($plugin);
  108. // The following request will get the mock response from the plugin in FIFO order
  109. $request = $client->get('http://www.test.com/');
  110. $request->send();
  111. // The MockPlugin maintains a list of requests that were mocked
  112. $this->assertContainsOnly($request, $plugin->getReceivedRequests());
  113. node.js web server for integration testing
  114. ------------------------------------------
  115. Using mock responses is usually enough when testing a web service client. If your client needs to add custom cURL
  116. options to requests, then you should use the node.js test web server to ensure that your HTTP request message is
  117. being created correctly.
  118. Guzzle is based around PHP's libcurl bindings. cURL sometimes modifies an HTTP request message based on
  119. ``CURLOPT_*`` options. Headers that are added to your request by cURL will not be accounted for if you inject mock
  120. responses into your tests. Additionally, some request entity bodies cannot be loaded by the client before transmitting
  121. it to the sever (for example, when using a client as a sort of proxy and streaming content from a remote server). You
  122. might also need to inspect the entity body of a ``multipart/form-data`` POST request.
  123. .. note::
  124. You can skip all of the tests that require the node.js test web server by excluding the ``server`` group:
  125. ``phpunit --exclude-group server``
  126. Using the test server
  127. ~~~~~~~~~~~~~~~~~~~~~
  128. The node.js test server receives requests and returns queued responses. The test server exposes a simple API that is
  129. used to enqueue responses and inspect the requests that it has received.
  130. Retrieve the server object by calling ``$this->getServer()``. If the node.js server is not running, it will be
  131. started as a forked process and an object that interfaces with the server will be returned. (note: stopping the
  132. server is handled internally by Guzzle.)
  133. You can queue an HTTP response or an array of responses by calling ``$this->getServer()->enqueue()``:
  134. .. code-block:: php
  135. $this->getServer()->enqueue("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
  136. The above code queues a single 200 response with an empty body. Responses are queued using a FIFO order; this
  137. response will be returned by the server when it receives the first request and then removed from the queue. If a
  138. request is received by a server with no queued responses, an exception will be thrown in your unit test.
  139. You can inspect the requests that the server has retrieved by calling ``$this->getServer()->getReceivedRequests()``.
  140. This method accepts an optional ``$hydrate`` parameter that specifies if you are retrieving an array of string HTTP
  141. requests or an array of ``Guzzle\Http\RequestInterface`` subclassed objects. "Hydrating" the requests will allow
  142. greater flexibility in your unit tests so that you can easily assert the state of the various parts of a request.
  143. You will need to modify the base_url of your web service client in order to use it against the test server.
  144. .. code-block:: php
  145. $client = $this->getServiceBuilder()->get('my_client');
  146. $client->setBaseUrl($this->getServer()->getUrl());
  147. After running the above code, all calls made from the ``$client`` object will be sent to the test web server.