@@ -6,7 +6,7 @@ The PHPUnit Bridge
6
6
==================
7
7
8
8
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 .
10
10
11
11
It comes with the following features:
12
12
@@ -18,6 +18,8 @@ It comes with the following features:
18
18
19
19
* Displays the stack trace of a deprecation on-demand;
20
20
21
+ * Provides a ``ClockMock `` helper class for time-sensitive tests.
22
+
21
23
.. versionadded :: 2.7
22
24
The PHPUnit Bridge was introduced in Symfony 2.7. It is however possible to
23
25
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.
120
122
This is useful to projects that must use deprecated interfaces for backward
121
123
compatibility reasons.
122
124
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
+
123
239
.. _PHPUnit : https://phpunit.de
124
240
.. _`PHPUnit event listener` : https://phpunit.de/manual/current/en/extending-phpunit.html#extending-phpunit.PHPUnit_Framework_TestListener
125
241
.. _`PHP error handler` : http://php.net/manual/en/book.errorfunc.php
0 commit comments