From 05316b562ed95fa2c0fb64e88b0d801e7f96635d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Mon, 15 Feb 2016 00:13:58 +0000 Subject: [PATCH 01/15] Add doc for the PHPUnit bridge component --- components/phpunit_bridge.rst | 128 ++++++++++++++++++++ images/components/phpunit_bridge/report.png | Bin 0 -> 47710 bytes 2 files changed, 128 insertions(+) create mode 100644 components/phpunit_bridge.rst create mode 100644 images/components/phpunit_bridge/report.png diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst new file mode 100644 index 00000000000..61555389c82 --- /dev/null +++ b/components/phpunit_bridge.rst @@ -0,0 +1,128 @@ +The PHPUnit Bridge Component +============================= + + The PHPUnit Bridge component provides utilities to report trigerred errors, + legacy tests and usage of deprecated code. + +It comes with the following features: + +* Enforce a consistent `C` locale (It forces applications to use the default +language for output) +* Auto-register `class_exists` to load Doctrine annotations (when used); +* Print a user deprecation notices summary at the end of the test suite; +* Display the stack trace of a deprecation on-demand. + +Installation +------------ + +You can install the component in 2 different ways: + +* :doc:`Install it via Composer ` + (``symfony/phpunit-bridge`` on `Packagist`_); as a dev dependency +* Use the official Git repository (https://github.com/symfony/phpunit-bridge). + +.. include:: /components/require_autoload.rst.inc + +Usage +----- + +Once the component installed, it automatically registers a +`PHPUnit event listener`_. This listener simply registers a `PHP error handler`_ +called `DeprecationErrorHandler`. After running your PHPUnit tests again, you +will have a similar report: + +.. image:: /images/components/phpunit_bridge/report.png + +The summary includes: + +* **Unsilenced** reports deprecation notices that were triggered without the +recommended @-silencing operator; +* **Legacy** deprecation notices denote tests that explicitly test some legacy +interfaces. +* **Remaining/Other** deprecation notices are all other (non-legacy) notices, +grouped by message, test class and method. + +Trigger deprecation notices +--------------------------- + +Deprecation notices can be triggered by using: + + @trigger_error('Your deprecation message', E_USER_DEPRECATED); + +Without the @-silencing operator, users would need to opt-out from deprecation +notices. Silencing by default swaps this behavior and allows users to opt-in +when they are ready to cope with them (by adding a custom error handler like the +one provided by this bridge.) When not silenced, deprecation notices will appear +in the **Unsilenced** section of the deprecation report. + +Mark tests as legacy +-------------------- + +There are four ways to mark a test as legacy: + +* Make its class start with the `Legacy` prefix +* Make its method start with `testLegacy` +* Make its data provider start with `provideLegacy` or `getLegacy` +* Add the `@group legacy` annotation to its class or method + +Configuration +------------- + +In case you need to inspect the stack trace of a particular deprecation +triggered by your unit tests, you can set the `SYMFONY_DEPRECATIONS_HELPER` +`environment variable`_ to a regular expression that matches this deprecation's +message, encapsed between `/`. For example, with: + +.. configuration-block:: + + .. code-block:: xml + + + + + + + + + + + + tests + + + + + + + + + + + src + + src/*Bundle/Resources + src/*/*Bundle/Resources + src/*/Bundle/*Bundle/Resources + + + + + +PHPUnit_ will stop your test suite once a deprecation notice is triggered whose +message contains the `"foobar"` string. + +By default, any non-legacy-tagged or any non-@-silenced deprecation notices will +make tests fail. Alternatively, setting `SYMFONY_DEPRECATIONS_HELPER` to the +value `"weak"` will make the bridge ignore any deprecation notices. This is +useful to projects that must use deprecated interfaces for backward compatibility +reasons. + +.. _PHPUnit: https://phpunit.de +.. _`PHPUnit event listener`: https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener +.. _`PHP error handler`: http://php.net/manual/en/book.errorfunc.php +.. _`environment variable`: https://phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.php-ini-constants-variables diff --git a/images/components/phpunit_bridge/report.png b/images/components/phpunit_bridge/report.png new file mode 100644 index 0000000000000000000000000000000000000000..3a4534c13833b5a804ea555c1749af69b1995439 GIT binary patch literal 47710 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 literal 0 HcmV?d00001 From 5fe6bf0b3072573e046540301fddafa190a5f4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Mon, 15 Feb 2016 00:22:10 +0000 Subject: [PATCH 02/15] Fix linting --- components/phpunit_bridge.rst | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 61555389c82..5beffa393ec 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -6,8 +6,7 @@ The PHPUnit Bridge Component It comes with the following features: -* Enforce a consistent `C` locale (It forces applications to use the default -language for output) +* Enforce a consistent `C` locale (It forces applications to use the default language for output) * Auto-register `class_exists` to load Doctrine annotations (when used); * Print a user deprecation notices summary at the end of the test suite; * Display the stack trace of a deprecation on-demand. @@ -35,12 +34,9 @@ will have a similar report: The summary includes: -* **Unsilenced** reports deprecation notices that were triggered without the -recommended @-silencing operator; -* **Legacy** deprecation notices denote tests that explicitly test some legacy -interfaces. -* **Remaining/Other** deprecation notices are all other (non-legacy) notices, -grouped by message, test class and method. +* **Unsilenced** reports deprecation notices that were triggered without the recommended @-silencing operator; +* **Legacy** deprecation notices denote tests that explicitly test some legacy interfaces. +* **Remaining/Other** deprecation notices are all other (non-legacy) notices, grouped by message, test class and method. Trigger deprecation notices --------------------------- From eb27c9b149656b138c21bacc3a2c7ec744293c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Mon, 15 Feb 2016 00:34:51 +0000 Subject: [PATCH 03/15] Various fix --- components/index.rst | 1 + components/map.rst.inc | 6 +++++- components/phpunit_bridge.rst | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/components/index.rst b/components/index.rst index 780b33b2c9e..2aa2c782021 100644 --- a/components/index.rst +++ b/components/index.rst @@ -21,6 +21,7 @@ The Components http_kernel/index intl options_resolver + phpunit_bridge process property_access/index routing/index diff --git a/components/map.rst.inc b/components/map.rst.inc index b69b347373f..3d8bd3b5d5c 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -1,7 +1,7 @@ * :doc:`/components/using_components` * :doc:`/components/browser_kit/index` - + * :doc:`/components/browser_kit/introduction` * :doc:`/components/class_loader/index` @@ -100,6 +100,10 @@ * :doc:`/components/options_resolver` +* **PHPUnitBridge** + + * :doc:`/components/phpunit_bridge` + * **Process** * :doc:`/components/process` diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 5beffa393ec..eb5e8ef0e35 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -1,3 +1,7 @@ +.. index:: + single: PHPUnitBridge + single: Components; PHPUnitBridge + The PHPUnit Bridge Component ============================= @@ -122,3 +126,4 @@ reasons. .. _`PHPUnit event listener`: https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener .. _`PHP error handler`: http://php.net/manual/en/book.errorfunc.php .. _`environment variable`: https://phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.php-ini-constants-variables +.. _Packagist: https://packagist.org/packages/symfony/phpunit-bridge From ab94ab815096ac78e93308972e67e22265bffd85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Wed, 17 Feb 2016 14:59:53 +0000 Subject: [PATCH 04/15] Update --- components/phpunit_bridge.rst | 67 ++++++++++++++--------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index eb5e8ef0e35..f1183dbd57b 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -5,14 +5,15 @@ The PHPUnit Bridge Component ============================= - The PHPUnit Bridge component provides utilities to report trigerred errors, - legacy tests and usage of deprecated code. + The PHPUnit Bridge component provides utilities to report legacy tests and + usage of deprecated code. It comes with the following features: -* Enforce a consistent `C` locale (It forces applications to use the default language for output) -* Auto-register `class_exists` to load Doctrine annotations (when used); -* Print a user deprecation notices summary at the end of the test suite; +* Forces the application to use the default language locale for output (set the + locale to ``C``) +* Auto-register `class_exists` to load Doctrine annotations (when used) +* It displays the whole list of deprecated features used in the application * Display the stack trace of a deprecation on-demand. Installation @@ -22,7 +23,7 @@ You can install the component in 2 different ways: * :doc:`Install it via Composer ` (``symfony/phpunit-bridge`` on `Packagist`_); as a dev dependency -* Use the official Git repository (https://github.com/symfony/phpunit-bridge). +* Use the official Git repository (https://github.com/symfony/phpunit-bridge) .. include:: /components/require_autoload.rst.inc @@ -30,29 +31,32 @@ Usage ----- Once the component installed, it automatically registers a -`PHPUnit event listener`_. This listener simply registers a `PHP error handler`_ +`PHPUnit event listener`_ which in turn registers a `PHP error handler`_ called `DeprecationErrorHandler`. After running your PHPUnit tests again, you -will have a similar report: +will get a report similar to this one: .. image:: /images/components/phpunit_bridge/report.png The summary includes: -* **Unsilenced** reports deprecation notices that were triggered without the recommended @-silencing operator; -* **Legacy** deprecation notices denote tests that explicitly test some legacy interfaces. -* **Remaining/Other** deprecation notices are all other (non-legacy) notices, grouped by message, test class and method. +* **Unsilenced** reports deprecation notices that were triggered without the + recommended @-silencing operator +* **Legacy** deprecation notices denote tests that explicitly test some legacy + features +* **Remaining/Other** deprecation notices are all other (non-legacy) notices, + grouped by message, test class and method Trigger deprecation notices --------------------------- -Deprecation notices can be triggered by using: +Deprecation notices can be triggered by using:: @trigger_error('Your deprecation message', E_USER_DEPRECATED); Without the @-silencing operator, users would need to opt-out from deprecation notices. Silencing by default swaps this behavior and allows users to opt-in when they are ready to cope with them (by adding a custom error handler like the -one provided by this bridge.) When not silenced, deprecation notices will appear +one provided by this bridge). When not silenced, deprecation notices will appear in the **Unsilenced** section of the deprecation report. Mark tests as legacy @@ -60,16 +64,16 @@ Mark tests as legacy There are four ways to mark a test as legacy: -* Make its class start with the `Legacy` prefix -* Make its method start with `testLegacy` -* Make its data provider start with `provideLegacy` or `getLegacy` -* Add the `@group legacy` annotation to its class or method +* Make its class start with the ``Legacy`` prefix +* Make its method start with ``testLegacy`` +* Make its data provider start with ``provideLegacy`` or ``getLegacy`` +* Add the ``@group legacy`` annotation to its class or method Configuration ------------- In case you need to inspect the stack trace of a particular deprecation -triggered by your unit tests, you can set the `SYMFONY_DEPRECATIONS_HELPER` +triggered by your unit tests, you can set the ``SYMFONY_DEPRECATIONS_HELPER`` `environment variable`_ to a regular expression that matches this deprecation's message, encapsed between `/`. For example, with: @@ -86,39 +90,20 @@ message, encapsed between `/`. For example, with: colors="true" bootstrap="app/autoload.php" > - - - - - - - tests - - + - - - - src - - src/*Bundle/Resources - src/*/*Bundle/Resources - src/*/Bundle/*Bundle/Resources - - - PHPUnit_ will stop your test suite once a deprecation notice is triggered whose -message contains the `"foobar"` string. +message contains the ``"foobar"`` string. By default, any non-legacy-tagged or any non-@-silenced deprecation notices will -make tests fail. Alternatively, setting `SYMFONY_DEPRECATIONS_HELPER` to the -value `"weak"` will make the bridge ignore any deprecation notices. This is +make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to the +value ``"weak"`` will make the bridge ignore any deprecation notices. This is useful to projects that must use deprecated interfaces for backward compatibility reasons. From 891d2ff4d84fe360c4a0e181b666a6f88e69ab4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Wed, 17 Feb 2016 15:02:07 +0000 Subject: [PATCH 05/15] minor fixes --- components/phpunit_bridge.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index f1183dbd57b..da405e1edc1 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -12,7 +12,7 @@ It comes with the following features: * Forces the application to use the default language locale for output (set the locale to ``C``) -* Auto-register `class_exists` to load Doctrine annotations (when used) +* Auto-register ``class_exists`` to load Doctrine annotations (when used) * It displays the whole list of deprecated features used in the application * Display the stack trace of a deprecation on-demand. @@ -32,7 +32,7 @@ Usage Once the component installed, it automatically registers a `PHPUnit event listener`_ which in turn registers a `PHP error handler`_ -called `DeprecationErrorHandler`. After running your PHPUnit tests again, you +called ``DeprecationErrorHandler``. After running your PHPUnit tests again, you will get a report similar to this one: .. image:: /images/components/phpunit_bridge/report.png @@ -75,7 +75,7 @@ Configuration In case you need to inspect the stack trace of a particular deprecation triggered by your unit tests, you can set the ``SYMFONY_DEPRECATIONS_HELPER`` `environment variable`_ to a regular expression that matches this deprecation's -message, encapsed between `/`. For example, with: +message, encapsed between ``/``. For example, with: .. configuration-block:: From a91229963a5b0c86c19861460ecb6c5065a6cab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 15:02:03 +0000 Subject: [PATCH 06/15] Add SYMFONY_DEPRECATIONS_HELPER feature --- components/phpunit_bridge.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index da405e1edc1..b7673dbf5e8 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -75,7 +75,7 @@ Configuration In case you need to inspect the stack trace of a particular deprecation triggered by your unit tests, you can set the ``SYMFONY_DEPRECATIONS_HELPER`` `environment variable`_ to a regular expression that matches this deprecation's -message, encapsed between ``/``. For example, with: +message, encapsed between ``/`. For example, with: .. configuration-block:: @@ -102,8 +102,10 @@ PHPUnit_ will stop your test suite once a deprecation notice is triggered whose message contains the ``"foobar"`` string. By default, any non-legacy-tagged or any non-@-silenced deprecation notices will -make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to the -value ``"weak"`` will make the bridge ignore any deprecation notices. This is +make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to an +arbitrary value (ex: ``320``) will make the tests fails only if a higher number +of deprecation notices is reached (``0`` is the default value). You can also set +the value ``"weak"`` will make the bridge ignore any deprecation notices. This is useful to projects that must use deprecated interfaces for backward compatibility reasons. From cf8b0c4cd5ef43f16baa4bb48955d5925eff3262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 15:12:41 +0000 Subject: [PATCH 07/15] Address some comments --- components/phpunit_bridge.rst | 43 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index b7673dbf5e8..e27b8c20fed 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -10,11 +10,10 @@ The PHPUnit Bridge Component It comes with the following features: -* Forces the application to use the default language locale for output (set the - locale to ``C``) +* Forces the tests to use a consistent locale (``C``) * Auto-register ``class_exists`` to load Doctrine annotations (when used) * It displays the whole list of deprecated features used in the application -* Display the stack trace of a deprecation on-demand. +* Displays the stack trace of a deprecation on-demand. Installation ------------ @@ -32,21 +31,23 @@ Usage Once the component installed, it automatically registers a `PHPUnit event listener`_ which in turn registers a `PHP error handler`_ -called ``DeprecationErrorHandler``. After running your PHPUnit tests again, you -will get a report similar to this one: +called ``DeprecationErrorHandler``. After running your PHPUnit tests, you will +get a report similar to this one: .. image:: /images/components/phpunit_bridge/report.png The summary includes: -* **Unsilenced** reports deprecation notices that were triggered without the - recommended @-silencing operator -* **Legacy** deprecation notices denote tests that explicitly test some legacy - features -* **Remaining/Other** deprecation notices are all other (non-legacy) notices, - grouped by message, test class and method +**Unsilenced** + Reports deprecation notices that were triggered without the recommended + @-silencing operator +**Legacy** + Deprecation notices denote tests that explicitly test some legacy features +**Remaining/Other** + Deprecation notices are all other (non-legacy) notices, grouped by message, + test class and method -Trigger deprecation notices +Trigger Deprecation Notices --------------------------- Deprecation notices can be triggered by using:: @@ -59,15 +60,15 @@ when they are ready to cope with them (by adding a custom error handler like the one provided by this bridge). When not silenced, deprecation notices will appear in the **Unsilenced** section of the deprecation report. -Mark tests as legacy +Mark Tests as Legacy -------------------- There are four ways to mark a test as legacy: +* (**Recommended**) Add the ``@group legacy`` annotation to its class or method * Make its class start with the ``Legacy`` prefix * Make its method start with ``testLegacy`` * Make its data provider start with ``provideLegacy`` or ``getLegacy`` -* Add the ``@group legacy`` annotation to its class or method Configuration ------------- @@ -75,21 +76,16 @@ Configuration In case you need to inspect the stack trace of a particular deprecation triggered by your unit tests, you can set the ``SYMFONY_DEPRECATIONS_HELPER`` `environment variable`_ to a regular expression that matches this deprecation's -message, encapsed between ``/`. For example, with: - -.. configuration-block:: +message, enclosed with ``/``. For example, with: .. code-block:: xml - - + + @@ -101,6 +97,9 @@ message, encapsed between ``/`. For example, with: PHPUnit_ will stop your test suite once a deprecation notice is triggered whose message contains the ``"foobar"`` string. +Making Tests Fail +----------------- + By default, any non-legacy-tagged or any non-@-silenced deprecation notices will make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to an arbitrary value (ex: ``320``) will make the tests fails only if a higher number From d38454bfe10c095970600470d4900969f52aea6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 15:33:41 +0000 Subject: [PATCH 08/15] minor fixes --- components/phpunit_bridge.rst | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index e27b8c20fed..43208df162c 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -40,12 +40,12 @@ The summary includes: **Unsilenced** Reports deprecation notices that were triggered without the recommended - @-silencing operator + @-silencing operator. **Legacy** - Deprecation notices denote tests that explicitly test some legacy features + Deprecation notices denote tests that explicitly test some legacy features. **Remaining/Other** Deprecation notices are all other (non-legacy) notices, grouped by message, - test class and method + test class and method. Trigger Deprecation Notices --------------------------- @@ -78,21 +78,21 @@ triggered by your unit tests, you can set the ``SYMFONY_DEPRECATIONS_HELPER`` `environment variable`_ to a regular expression that matches this deprecation's message, enclosed with ``/``. For example, with: - .. code-block:: xml +.. code-block:: xml - - - + + + - + - - - - - + + + + + PHPUnit_ will stop your test suite once a deprecation notice is triggered whose message contains the ``"foobar"`` string. From bfe2e765c55d4029571a6bd2a63ec99aff631523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 15:52:32 +0000 Subject: [PATCH 09/15] Add link for @-silence operator --- components/phpunit_bridge.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 43208df162c..95697381dae 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -84,7 +84,6 @@ message, enclosed with ``/``. For example, with: - From d5f73957e55a533c1b0c2b102dc008cbab09239c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 16:01:33 +0000 Subject: [PATCH 10/15] Drop 'Component' from the name --- components/phpunit_bridge.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 95697381dae..1de36f618da 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -2,8 +2,8 @@ single: PHPUnitBridge single: Components; PHPUnitBridge -The PHPUnit Bridge Component -============================= +The PHPUnit Bridge +================== The PHPUnit Bridge component provides utilities to report legacy tests and usage of deprecated code. @@ -40,7 +40,7 @@ The summary includes: **Unsilenced** Reports deprecation notices that were triggered without the recommended - @-silencing operator. + `@-silencing operator`_. **Legacy** Deprecation notices denote tests that explicitly test some legacy features. **Remaining/Other** @@ -54,7 +54,7 @@ Deprecation notices can be triggered by using:: @trigger_error('Your deprecation message', E_USER_DEPRECATED); -Without the @-silencing operator, users would need to opt-out from deprecation +Without the `@-silencing operator`_, users would need to opt-out from deprecation notices. Silencing by default swaps this behavior and allows users to opt-in when they are ready to cope with them (by adding a custom error handler like the one provided by this bridge). When not silenced, deprecation notices will appear @@ -99,7 +99,7 @@ message contains the ``"foobar"`` string. Making Tests Fail ----------------- -By default, any non-legacy-tagged or any non-@-silenced deprecation notices will +By default, any non-legacy-tagged or any non-`@-silenced`_ deprecation notices will make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to an arbitrary value (ex: ``320``) will make the tests fails only if a higher number of deprecation notices is reached (``0`` is the default value). You can also set @@ -112,3 +112,5 @@ reasons. .. _`PHP error handler`: http://php.net/manual/en/book.errorfunc.php .. _`environment variable`: https://phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.php-ini-constants-variables .. _Packagist: https://packagist.org/packages/symfony/phpunit-bridge +.. _`@-silencing operator` http://php.net/manual/en/language.operators.errorcontrol.php +.. _`@-silenced` http://php.net/manual/en/language.operators.errorcontrol.php From 54001a89b54b9707ebeb4b5d0003f7b6b26c5edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 16:22:15 +0000 Subject: [PATCH 11/15] Add doc for the ClockMock --- components/phpunit_bridge.rst | 40 ++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 1de36f618da..aad486b62f6 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -5,15 +5,16 @@ The PHPUnit Bridge ================== - The PHPUnit Bridge component provides utilities to report legacy tests and - usage of deprecated code. + The PHPUnit Bridge component provides utilities to report legacy tests, and + usage of deprecated code a `ClockMock` for time-sensitive tests. It comes with the following features: * Forces the tests to use a consistent locale (``C``) * Auto-register ``class_exists`` to load Doctrine annotations (when used) * It displays the whole list of deprecated features used in the application -* Displays the stack trace of a deprecation on-demand. +* Displays the stack trace of a deprecation on-demand +* Provides a `ClockMock` class for time-sensitive tests Installation ------------ @@ -107,10 +108,39 @@ the value ``"weak"`` will make the bridge ignore any deprecation notices. This i useful to projects that must use deprecated interfaces for backward compatibility reasons. +Time-sensitive Tests +-------------------- + +The mock class ``ClockMock`` allows you to mock the time functions ``time()``, +``microtime()``, ``sleep()`` and ``usleep()``. + +For example, assuming you have the following code: + +.. code-block:: php + + $stopwatch = new Stopwatch(); + + $stopwatch->start(); + sleep(1); + $duration = $stopwatch->stop(); + + $this->assertEquals(1, $duration); + +You used the :doc:`Symfony Stopwatch Component ` to +calculate the duration time of your process, here 1 second. However, this test +may fail because of the duration time might actually be `1.000023s`. + +To use the ``ClockMock`` in your test, you can: + +* (**Recommended**) Add the ``@group time-sensitive`` annotation to its class or method +* Register it manually by calling ``\Symfony\Bridge\PhpUnit\ClockMock::register(true)`` + (before the test) and ``Symfony\Bridge\PhpUnit\ClockMock::register(false)`` + (after the test) + .. _PHPUnit: https://phpunit.de .. _`PHPUnit event listener`: https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener .. _`PHP error handler`: http://php.net/manual/en/book.errorfunc.php .. _`environment variable`: https://phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.php-ini-constants-variables .. _Packagist: https://packagist.org/packages/symfony/phpunit-bridge -.. _`@-silencing operator` http://php.net/manual/en/language.operators.errorcontrol.php -.. _`@-silenced` http://php.net/manual/en/language.operators.errorcontrol.php +.. _`@-silencing operator`: http://php.net/manual/en/language.operators.errorcontrol.php +.. _`@-silenced`: http://php.net/manual/en/language.operators.errorcontrol.php From 57a1ce1f05a9c37a1421df8e457a8cf1ebe9bc58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 16:48:41 +0000 Subject: [PATCH 12/15] Fix typo in intro --- components/phpunit_bridge.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index aad486b62f6..3652418b940 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -6,7 +6,7 @@ The PHPUnit Bridge ================== The PHPUnit Bridge component provides utilities to report legacy tests, and - usage of deprecated code a `ClockMock` for time-sensitive tests. + usage of deprecated code and a helper for time-sensitive tests. It comes with the following features: @@ -14,7 +14,7 @@ It comes with the following features: * Auto-register ``class_exists`` to load Doctrine annotations (when used) * It displays the whole list of deprecated features used in the application * Displays the stack trace of a deprecation on-demand -* Provides a `ClockMock` class for time-sensitive tests +* Provides a `ClockMock` mock class for time-sensitive tests Installation ------------ From 4a5c951a88983cb04c8e8cfbc7808629fc10ca7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sat, 27 Feb 2016 22:58:32 +0000 Subject: [PATCH 13/15] Fix @xabbuh comments --- components/phpunit_bridge.rst | 56 +++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 3652418b940..24d071eede9 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -5,16 +5,20 @@ The PHPUnit Bridge ================== - The PHPUnit Bridge component provides utilities to report legacy tests, and - usage of deprecated code and a helper for time-sensitive tests. + The PHPUnit Bridge provides utilities to report legacy tests, and usage of + deprecated code and a helper for time-sensitive tests. It comes with the following features: -* Forces the tests to use a consistent locale (``C``) -* Auto-register ``class_exists`` to load Doctrine annotations (when used) -* It displays the whole list of deprecated features used in the application -* Displays the stack trace of a deprecation on-demand -* Provides a `ClockMock` mock class for time-sensitive tests +* Forces the tests to use a consistent locale (``C``); + +* Auto-register ``class_exists`` to load Doctrine annotations (when used); + +* It displays the whole list of deprecated features used in the application; + +* Displays the stack trace of a deprecation on-demand; + +* Provides a `ClockMock` mock class for time-sensitive tests. Installation ------------ @@ -22,8 +26,9 @@ Installation You can install the component in 2 different ways: * :doc:`Install it via Composer ` - (``symfony/phpunit-bridge`` on `Packagist`_); as a dev dependency -* Use the official Git repository (https://github.com/symfony/phpunit-bridge) + (``symfony/phpunit-bridge`` on `Packagist`_); as a dev dependency; + +* Use the official Git repository (https://github.com/symfony/phpunit-bridge). .. include:: /components/require_autoload.rst.inc @@ -42,8 +47,10 @@ The summary includes: **Unsilenced** Reports deprecation notices that were triggered without the recommended `@-silencing operator`_. + **Legacy** Deprecation notices denote tests that explicitly test some legacy features. + **Remaining/Other** Deprecation notices are all other (non-legacy) notices, grouped by message, test class and method. @@ -66,10 +73,13 @@ Mark Tests as Legacy There are four ways to mark a test as legacy: -* (**Recommended**) Add the ``@group legacy`` annotation to its class or method -* Make its class start with the ``Legacy`` prefix -* Make its method start with ``testLegacy`` -* Make its data provider start with ``provideLegacy`` or ``getLegacy`` +* (**Recommended**) Add the ``@group legacy`` annotation to its class or method; + +* Make its class start with the ``Legacy`` prefix; + +* Make its method start with ``testLegacy``; + +* Make its data provider start with ``provideLegacy`` or ``getLegacy``. Configuration ------------- @@ -104,19 +114,17 @@ By default, any non-legacy-tagged or any non-`@-silenced`_ deprecation notices w make tests fail. Alternatively, setting ``SYMFONY_DEPRECATIONS_HELPER`` to an arbitrary value (ex: ``320``) will make the tests fails only if a higher number of deprecation notices is reached (``0`` is the default value). You can also set -the value ``"weak"`` will make the bridge ignore any deprecation notices. This is -useful to projects that must use deprecated interfaces for backward compatibility -reasons. +the value ``"weak"`` which will make the bridge ignore any deprecation notices. +This is useful to projects that must use deprecated interfaces for backward +compatibility reasons. Time-sensitive Tests -------------------- -The mock class ``ClockMock`` allows you to mock the time functions ``time()``, +The ``ClockMock`` class allows you to mock the time functions ``time()``, ``microtime()``, ``sleep()`` and ``usleep()``. -For example, assuming you have the following code: - -.. code-block:: php +For example, assuming you have the following code:: $stopwatch = new Stopwatch(); @@ -130,12 +138,14 @@ You used the :doc:`Symfony Stopwatch Component ` to calculate the duration time of your process, here 1 second. However, this test may fail because of the duration time might actually be `1.000023s`. -To use the ``ClockMock`` in your test, you can: +To use the ``ClockMock`` class in your test, you can: + +* (**Recommended**) Add the ``@group time-sensitive`` annotation to its class or + method; -* (**Recommended**) Add the ``@group time-sensitive`` annotation to its class or method * Register it manually by calling ``\Symfony\Bridge\PhpUnit\ClockMock::register(true)`` (before the test) and ``Symfony\Bridge\PhpUnit\ClockMock::register(false)`` - (after the test) + (after the test). .. _PHPUnit: https://phpunit.de .. _`PHPUnit event listener`: https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener From 8b29f8965335edc9583e34bda1c5254991ba2473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Tue, 1 Mar 2016 22:35:59 +0000 Subject: [PATCH 14/15] Enhance clock mocking doc --- components/phpunit_bridge.rst | 106 ++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 10 deletions(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 24d071eede9..49058701b1b 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -121,22 +121,42 @@ compatibility reasons. Time-sensitive Tests -------------------- -The ``ClockMock`` class allows you to mock the time functions ``time()``, -``microtime()``, ``sleep()`` and ``usleep()``. +Use Case +~~~~~~~~ -For example, assuming you have the following code:: +If you have this kind of time-related tests:: - $stopwatch = new Stopwatch(); + use Symfony\Component\Stopwatch\Stopwatch; - $stopwatch->start(); - sleep(1); - $duration = $stopwatch->stop(); + class MyTest extends \PHPUnit_Framework_TestCase + { + public function testSomething() + { + $stopwatch = new Stopwatch(); - $this->assertEquals(1, $duration); + $stopwatch->start(); + sleep(10); + $duration = $stopwatch->stop(); + + $this->assertEquals(10, $duration); + } + } You used the :doc:`Symfony Stopwatch Component ` to -calculate the duration time of your process, here 1 second. However, this test -may fail because of the duration time might actually be `1.000023s`. +calculate the duration time of your process, here 10 seconds. However, depending +on the load of the server your the processes running on your local machine, the +``$duration`` could for example be `10.000023s` instead of `10s`. + +This kind of tests are called transient tests: they are failing randomly +depending on spurious and external circumstances. They are often cause trouble +when using public continuous integration services like `Travis CI`_. + +Clock Mocking +~~~~~~~~~~~~~ + +The ``ClockMock`` class provided by this bridge allows you to mock the PHP's +built-in time functions ``time()``, ``microtime()``, ``sleep()`` and +``usleep()``. To use the ``ClockMock`` class in your test, you can: @@ -147,6 +167,71 @@ To use the ``ClockMock`` class in your test, you can: (before the test) and ``Symfony\Bridge\PhpUnit\ClockMock::register(false)`` (after the test). +As a result, the following is guarenteed to work and is no longer a transient +test: + +.. code-block:: php + + use Symfony\Component\Stopwatch\Stopwatch; + + /** + * @group time-sensitive + */ + class MyTest extends \PHPUnit_Framework_TestCase + { + public function testSomething() + { + $stopwatch = new Stopwatch(); + + $stopwatch->start(); + sleep(10); + $duration = $stopwatch->stop(); + + $this->assertEquals(10, $duration); + } + } + +And that's all! + +An added bonus of using the ``ClockMock`` class is that time passes instantly. +Using PHP's ``sleep(10)`` will make your test wait for 10 actual seconds (more +or less). In contrast, the ``ClockMock`` class advances the internal clock the +given number of seconds without actually waiting that time, so your test will +execute 10 seconds faster. + +Troubleshooting +~~~~~~~~~~~~~~~ + +The ``@group time-sensitive`` works "by convention" and assumes that the +namespace of the tested class can be obtained just by removing the ``\Tests\`` +part from the test namespace. I.e. that if the your test case fully-qualified +class name (FQCN) is ``App\Tests\Watch\DummyWatchTest``, it assumes the tested +class FQCN is ``App\Watch\DummyWatch``. + +If this convention doesn't work for your application, you can also configure +the mocked namespaces in the `phpunit.xml` file, as done for example in the +:doc:`HttpKernel Component `: + +.. code-block:: xml + + + + + + + + + + + Symfony\Component\HttpFoundation + + + + + + .. _PHPUnit: https://phpunit.de .. _`PHPUnit event listener`: https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener .. _`PHP error handler`: http://php.net/manual/en/book.errorfunc.php @@ -154,3 +239,4 @@ To use the ``ClockMock`` class in your test, you can: .. _Packagist: https://packagist.org/packages/symfony/phpunit-bridge .. _`@-silencing operator`: http://php.net/manual/en/language.operators.errorcontrol.php .. _`@-silenced`: http://php.net/manual/en/language.operators.errorcontrol.php +.. _`Travis CI`: https://travis-ci.com/ From d7c2adc0c93477e0b78dd9f1dc29101da8d043d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Fri, 4 Mar 2016 13:36:18 +0000 Subject: [PATCH 15/15] typo --- components/phpunit_bridge.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 49058701b1b..b10d22b09a1 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -5,7 +5,7 @@ The PHPUnit Bridge ================== - The PHPUnit Bridge provides utilities to report legacy tests, and usage of + The PHPUnit Bridge provides utilities to report legacy tests and usage of deprecated code and a helper for time-sensitive tests. It comes with the following features: