PageRenderTime 23ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/doc/testing.rst

http://github.com/fabpot/Silex
ReStructuredText | 222 lines | 166 code | 56 blank | 0 comment | 0 complexity | a4a1a3cc8c1d721f1da03ba378cca3a0 MD5 | raw file
  1. Testing
  2. =======
  3. Because Silex is built on top of Symfony, it is very easy to write functional
  4. tests for your application. Functional tests are automated software tests that
  5. ensure that your code is working correctly. They go through the user interface,
  6. using a fake browser, and mimic the actions a user would do.
  7. Why
  8. ---
  9. If you are not familiar with software tests, you may be wondering why you would
  10. need this. Every time you make a change to your application, you have to test
  11. it. This means going through all the pages and making sure they are still
  12. working. Functional tests save you a lot of time, because they enable you to
  13. test your application in usually under a second by running a single command.
  14. For more information on functional testing, unit testing, and automated
  15. software tests in general, check out `PHPUnit
  16. <https://github.com/sebastianbergmann/phpunit>`_ and `Bulat Shakirzyanov's talk
  17. on Clean Code <http://www.slideshare.net/avalanche123/clean-code-5609451>`_.
  18. PHPUnit
  19. -------
  20. `PHPUnit <https://github.com/sebastianbergmann/phpunit>`_ is the de-facto
  21. standard testing framework for PHP. It was built for writing unit tests, but it
  22. can be used for functional tests too. You write tests by creating a new class,
  23. that extends the ``PHPUnit_Framework_TestCase``. Your test cases are methods
  24. prefixed with ``test``::
  25. class ContactFormTest extends \PHPUnit_Framework_TestCase
  26. {
  27. public function testInitialPage()
  28. {
  29. ...
  30. }
  31. }
  32. In your test cases, you do assertions on the state of what you are testing. In
  33. this case we are testing a contact form, so we would want to assert that the
  34. page loaded correctly and contains our form::
  35. public function testInitialPage()
  36. {
  37. $statusCode = ...
  38. $pageContent = ...
  39. $this->assertEquals(200, $statusCode);
  40. $this->assertContains('Contact us', $pageContent);
  41. $this->assertContains('<form', $pageContent);
  42. }
  43. Here you see some of the available assertions. There is a full list available
  44. in the `Writing Tests for PHPUnit
  45. <https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html>`_
  46. section of the PHPUnit documentation.
  47. WebTestCase
  48. -----------
  49. Symfony provides a WebTestCase class that can be used to write functional
  50. tests. The Silex version of this class is ``Silex\WebTestCase``, and you can
  51. use it by making your test extend it::
  52. use Silex\WebTestCase;
  53. class ContactFormTest extends WebTestCase
  54. {
  55. ...
  56. }
  57. .. caution::
  58. If you need to override the ``setUp()`` method, don't forget to call the
  59. parent (``parent::setUp()``) to call the Silex default setup.
  60. .. note::
  61. If you want to use the Symfony ``WebTestCase`` class you will need to
  62. explicitly install its dependencies for your project:
  63. .. code-block:: bash
  64. composer require --dev symfony/browser-kit symfony/css-selector
  65. For your WebTestCase, you will have to implement a ``createApplication``
  66. method, which returns your application instance::
  67. public function createApplication()
  68. {
  69. // app.php must return an Application instance
  70. return require __DIR__.'/path/to/app.php';
  71. }
  72. Make sure you do **not** use ``require_once`` here, as this method will be
  73. executed before every test.
  74. .. tip::
  75. By default, the application behaves in the same way as when using it from a
  76. browser. But when an error occurs, it is sometimes easier to get raw
  77. exceptions instead of HTML pages. It is rather simple if you tweak the
  78. application configuration in the ``createApplication()`` method like
  79. follows::
  80. public function createApplication()
  81. {
  82. $app = require __DIR__.'/path/to/app.php';
  83. $app['debug'] = true;
  84. unset($app['exception_handler']);
  85. return $app;
  86. }
  87. .. tip::
  88. If your application use sessions, set ``session.test`` to ``true`` to
  89. simulate sessions::
  90. public function createApplication()
  91. {
  92. // ...
  93. $app['session.test'] = true;
  94. // ...
  95. }
  96. The WebTestCase provides a ``createClient`` method. A client acts as a browser,
  97. and allows you to interact with your application. Here's how it works::
  98. public function testInitialPage()
  99. {
  100. $client = $this->createClient();
  101. $crawler = $client->request('GET', '/');
  102. $this->assertTrue($client->getResponse()->isOk());
  103. $this->assertCount(1, $crawler->filter('h1:contains("Contact us")'));
  104. $this->assertCount(1, $crawler->filter('form'));
  105. ...
  106. }
  107. There are several things going on here. You have both a ``Client`` and a
  108. ``Crawler``.
  109. You can also access the application through ``$this->app``.
  110. Client
  111. ~~~~~~
  112. The client represents a browser. It holds your browsing history, cookies and
  113. more. The ``request`` method allows you to make a request to a page on your
  114. application.
  115. .. note::
  116. You can find some documentation for it in `the client section of the
  117. testing chapter of the Symfony documentation
  118. <http://symfony.com/doc/current/book/testing.html#the-test-client>`_.
  119. Crawler
  120. ~~~~~~~
  121. The crawler allows you to inspect the content of a page. You can filter it
  122. using CSS expressions and lots more.
  123. .. note::
  124. You can find some documentation for it in `the crawler section of the testing
  125. chapter of the Symfony documentation
  126. <http://symfony.com/doc/current/book/testing.html#the-test-client>`_.
  127. Configuration
  128. -------------
  129. The suggested way to configure PHPUnit is to create a ``phpunit.xml.dist``
  130. file, a ``tests`` folder and your tests in
  131. ``tests/YourApp/Tests/YourTest.php``. The ``phpunit.xml.dist`` file should
  132. look like this:
  133. .. code-block:: xml
  134. <?xml version="1.0" encoding="UTF-8"?>
  135. <phpunit bootstrap="./vendor/autoload.php"
  136. backupGlobals="false"
  137. backupStaticAttributes="false"
  138. colors="true"
  139. convertErrorsToExceptions="true"
  140. convertNoticesToExceptions="true"
  141. convertWarningsToExceptions="true"
  142. processIsolation="false"
  143. stopOnFailure="false"
  144. syntaxCheck="false"
  145. >
  146. <testsuites>
  147. <testsuite name="YourApp Test Suite">
  148. <directory>./tests/</directory>
  149. </testsuite>
  150. </testsuites>
  151. </phpunit>
  152. Your ``tests/YourApp/Tests/YourTest.php`` should look like this::
  153. namespace YourApp\Tests;
  154. use Silex\WebTestCase;
  155. class YourTest extends WebTestCase
  156. {
  157. public function createApplication()
  158. {
  159. return require __DIR__.'/../../../app.php';
  160. }
  161. public function testFooBar()
  162. {
  163. ...
  164. }
  165. }
  166. Now, when running ``phpunit`` on the command line, tests should run.