@@ -6,7 +6,7 @@ The PHPUnit Bridge
66==================
77
88 The PHPUnit Bridge provides utilities to report legacy tests and usage of
9- deprecated code.
9+ deprecated code and a helper for time-sensitive tests .
1010
1111It comes with the following features:
1212
@@ -18,6 +18,8 @@ It comes with the following features:
1818
1919* Displays the stack trace of a deprecation on-demand;
2020
21+ * Provides a ``ClockMock `` helper class for time-sensitive tests.
22+
2123.. versionadded :: 2.7
2224 The PHPUnit Bridge was introduced in Symfony 2.7. It is however possible to
2325 install the bridge in any Symfony application (even 2.3).
@@ -120,6 +122,120 @@ the value ``"weak"`` which will make the bridge ignore any deprecation notices.
120122This is useful to projects that must use deprecated interfaces for backward
121123compatibility reasons.
122124
125+ Time-sensitive Tests
126+ ---------------------
127+
128+ Use Case
129+ ~~~~~~~~
130+
131+ If you have this kind of time-related tests::
132+
133+ use Symfony\Component\Stopwatch\Stopwatch;
134+
135+ class MyTest extends \PHPUnit_Framework_TestCase
136+ {
137+ public function testSomething()
138+ {
139+ $stopwatch = new Stopwatch();
140+
141+ $stopwatch->start();
142+ sleep(10);
143+ $duration = $stopwatch->stop();
144+
145+ $this->assertEquals(10, $duration);
146+ }
147+ }
148+
149+ You used the :doc: `Symfony Stopwatch Component </components/stopwatch >` to
150+ calculate the duration time of your process, here 10 seconds. However, depending
151+ on the load of the server your the processes running on your local machine, the
152+ ``$duration `` could for example be `10.000023s ` instead of `10s `.
153+
154+ This kind of tests are called transient tests: they are failing randomly
155+ depending on spurious and external circumstances. They are often cause trouble
156+ when using public continuous integration services like `Travis CI `_.
157+
158+ Clock Mocking
159+ ~~~~~~~~~~~~~
160+
161+ The :class: `Symfony\\ Bridge\\ PhpUnit\\ ClockMock ` class provided by this bridge
162+ allows you to mock the PHP's built-in time functions ``time() ``,
163+ ``microtime() ``, ``sleep() `` and ``usleep() ``.
164+
165+ To use the ``ClockMock `` class in your test, you can:
166+
167+ * (**Recommended **) Add the ``@group time-sensitive `` annotation to its class or
168+ method;
169+
170+ * Register it manually by calling ``ClockMock::register(__CLASS__) `` and
171+ ``ClockMock::withClockMock(true) `` before the test and
172+ ``ClockMock::withClockMock(false) `` after the test.
173+
174+ As a result, the following is guarenteed to work and is no longer a transient
175+ test::
176+
177+ use Symfony\Component\Stopwatch\Stopwatch;
178+
179+ /**
180+ * @group time-sensitive
181+ */
182+ class MyTest extends \PHPUnit_Framework_TestCase
183+ {
184+ public function testSomething()
185+ {
186+ $stopwatch = new Stopwatch();
187+
188+ $stopwatch->start();
189+ sleep(10);
190+ $duration = $stopwatch->stop();
191+
192+ $this->assertEquals(10, $duration);
193+ }
194+ }
195+
196+ And that's all!
197+
198+ .. tip ::
199+
200+ An added bonus of using the ``ClockMock `` class is that time passes
201+ instantly. Using PHP's ``sleep(10) `` will make your test wait for 10
202+ actual seconds (more or less). In contrast, the ``ClockMock `` class
203+ advances the internal clock the given number of seconds without actually
204+ waiting that time, so your test will execute 10 seconds faster.
205+
206+ Troubleshooting
207+ ~~~~~~~~~~~~~~~
208+
209+ The ``@group time-sensitive `` works "by convention" and assumes that the
210+ namespace of the tested class can be obtained just by removing the ``\Tests\ ``
211+ part from the test namespace. I.e. that if the your test case fully-qualified
212+ class name (FQCN) is ``App\Tests\Watch\DummyWatchTest ``, it assumes the tested
213+ class FQCN is ``App\Watch\DummyWatch ``.
214+
215+ If this convention doesn't work for your application, you can also configure
216+ the mocked namespaces in the ``phpunit.xml `` file, as done for example in the
217+ :doc: `HttpKernel Component </components/http_kernel/introduction >`:
218+
219+ .. code-block :: xml
220+
221+ <!-- http://phpunit.de/manual/4.1/en/appendixes.configuration.html -->
222+ <phpunit xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
223+ xsi : noNamespaceSchemaLocation =" http://schema.phpunit.de/4.1/phpunit.xsd"
224+ >
225+
226+ <!-- ... -->
227+
228+ <listeners >
229+ <listener class =" Symfony\Bridge\PhpUnit\SymfonyTestsListener" >
230+ <arguments >
231+ <array >
232+ <element ><string >Symfony\Component\HttpFoundation</string ></element >
233+ </array >
234+ </arguments >
235+ </listener >
236+ </listeners >
237+ </phpunit >
238+
123239 .. _PHPUnit : https://phpunit.de
124240.. _`PHPUnit event listener` : https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener
125241.. _`PHP error handler` : http://php.net/manual/en/book.errorfunc.php
0 commit comments