Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
189 | * Test the deferred resolving under different circumstances. |
||
190 | */ |
||
191 | class DeferredTest extends \PHPUnit_Framework_TestCase |
||
192 | { |
||
193 | /** |
||
194 | * @var Processor |
||
195 | */ |
||
196 | protected $processor; |
||
197 | |||
198 | /** |
||
199 | * Test a simple single deferred field. |
||
200 | */ |
||
201 | public function testSingleResolve(): void |
||
202 | { |
||
203 | $query = 'query { |
||
204 | users(ids: ["a", "b"]) { |
||
205 | name |
||
206 | } |
||
207 | }'; |
||
208 | $database = $this->prophesize(DeferredDatabase::class); |
||
209 | |||
210 | $database->query(['a', 'b'])->willReturn( |
||
211 | [ |
||
212 | 'a' => ['id' => 'a', 'name' => 'User A'], |
||
213 | 'b' => ['id' => 'b', 'name' => 'User B'], |
||
214 | ] |
||
215 | )->shouldBeCalledTimes(1); |
||
216 | |||
217 | $result = $this->query( |
||
218 | $query, |
||
219 | new DeferredQueryBuffer($database->reveal()) |
||
220 | ); |
||
221 | |||
222 | $database->checkProphecyMethodsPredictions(); |
||
223 | |||
224 | $this->assertEquals( |
||
225 | [ |
||
226 | 'users' => [ |
||
227 | ['name' => 'User A'], |
||
228 | ['name' => 'User B'], |
||
229 | ], |
||
230 | ], |
||
231 | $result['data'], |
||
232 | 'Retrieved correct data.' |
||
233 | ); |
||
234 | } |
||
235 | |||
236 | /** |
||
237 | * Test if multiple calls to the same field result in a single query. |
||
238 | */ |
||
239 | public function testMultiResolve(): void |
||
240 | { |
||
241 | $query = 'query { |
||
242 | a:users(ids: ["a"]) { |
||
243 | name |
||
244 | } |
||
245 | b:users(ids: ["b"]) { |
||
246 | name |
||
247 | } |
||
248 | }'; |
||
249 | |||
250 | $database = $this->prophesize(DeferredDatabase::class); |
||
251 | |||
252 | $database->query(['a', 'b'])->willReturn( |
||
253 | [ |
||
254 | 'a' => ['id' => 'a', 'name' => 'User A'], |
||
255 | 'b' => ['id' => 'b', 'name' => 'User B'], |
||
256 | ] |
||
257 | )->shouldBeCalledTimes(1); |
||
258 | |||
259 | $result = $this->query( |
||
260 | $query, |
||
261 | new DeferredQueryBuffer($database->reveal()) |
||
262 | ); |
||
263 | |||
264 | $database->checkProphecyMethodsPredictions(); |
||
265 | |||
266 | $this->assertEquals( |
||
267 | [ |
||
268 | 'a' => [ |
||
269 | ['name' => 'User A'], |
||
270 | ], |
||
271 | 'b' => [ |
||
272 | ['name' => 'User B'], |
||
273 | ], |
||
274 | ], |
||
275 | $result['data'], |
||
276 | 'Retrieved correct data.' |
||
277 | ); |
||
278 | } |
||
279 | |||
280 | /** |
||
281 | * Test if recursive deferred resolvers work properly. |
||
282 | */ |
||
283 | public function testRecursiveResolve(): void |
||
284 | { |
||
285 | $query = 'query { |
||
286 | a:users(ids: ["a"]) { |
||
287 | name |
||
288 | friends { |
||
289 | name |
||
290 | } |
||
291 | } |
||
292 | }'; |
||
293 | |||
294 | $database = $this->prophesize(DeferredDatabase::class); |
||
295 | |||
296 | $database->query(['a'])->willReturn( |
||
297 | [ |
||
298 | 'a' => ['id' => 'a', 'name' => 'User A', 'friends' => ['b', 'c']], |
||
299 | ] |
||
300 | )->shouldBeCalledTimes(1); |
||
301 | |||
302 | $database->query(['b', 'c'])->willReturn( |
||
303 | [ |
||
304 | 'b' => ['id' => 'b', 'name' => 'User B'], |
||
305 | 'c' => ['id' => 'c', 'name' => 'User C'], |
||
306 | ] |
||
307 | ); |
||
308 | |||
309 | $result = $this->query( |
||
310 | $query, |
||
311 | new DeferredQueryBuffer($database->reveal()) |
||
312 | ); |
||
313 | |||
314 | $database->checkProphecyMethodsPredictions(); |
||
315 | |||
316 | $this->assertEquals( |
||
317 | [ |
||
318 | 'a' => [ |
||
319 | [ |
||
320 | 'name' => 'User A', |
||
321 | 'friends' => [ |
||
322 | ['name' => 'User B'], |
||
323 | ['name' => 'User C'], |
||
324 | ], |
||
325 | ], |
||
326 | ], |
||
327 | ], |
||
328 | $result['data'], |
||
329 | 'Retrieved correct data.' |
||
330 | ); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Test if multiple deferred resolvers are optimized into two queries. |
||
335 | */ |
||
336 | public function testMultiRecursiveResolve(): void |
||
337 | { |
||
338 | $query = 'query { |
||
339 | a:users(ids: ["a"]) { |
||
340 | name |
||
341 | friends { |
||
342 | name |
||
343 | } |
||
344 | foes { |
||
345 | name |
||
346 | } |
||
347 | } |
||
348 | b:users(ids: ["b"]) { |
||
349 | name |
||
350 | friends { |
||
351 | name |
||
352 | } |
||
353 | foes { |
||
354 | name |
||
355 | } |
||
356 | } |
||
357 | }'; |
||
358 | |||
359 | $database = $this->prophesize(DeferredDatabase::class); |
||
360 | |||
361 | $database->query(['a', 'b'])->willReturn( |
||
362 | [ |
||
363 | 'a' => [ |
||
364 | 'id' => 'a', |
||
365 | 'name' => 'User A', |
||
366 | 'friends' => ['b', 'c'], |
||
367 | 'foes' => ['d', 'e'], |
||
368 | ], |
||
369 | 'b' => [ |
||
370 | 'id' => 'b', |
||
371 | 'name' => 'User B', |
||
372 | 'friends' => ['a'], |
||
373 | 'foes' => ['c'], |
||
374 | ], |
||
375 | ] |
||
376 | )->shouldBeCalledTimes(1); |
||
377 | |||
378 | $database->query(['a', 'b', 'c', 'd', 'e'])->willReturn( |
||
379 | [ |
||
380 | 'a' => ['id' => 'a', 'name' => 'User A'], |
||
381 | 'b' => ['id' => 'b', 'name' => 'User B'], |
||
382 | 'c' => ['id' => 'c', 'name' => 'User C'], |
||
383 | 'd' => ['id' => 'd', 'name' => 'User D'], |
||
384 | 'e' => ['id' => 'e', 'name' => 'User E'], |
||
385 | ] |
||
386 | )->shouldBeCalledTimes(1); |
||
387 | |||
388 | $result = $this->query( |
||
389 | $query, |
||
390 | new DeferredQueryBuffer($database->reveal()) |
||
391 | ); |
||
392 | |||
393 | $database->checkProphecyMethodsPredictions(); |
||
394 | |||
395 | $this->assertEquals( |
||
396 | [ |
||
397 | 'a' => [ |
||
398 | [ |
||
399 | 'name' => 'User A', |
||
400 | 'friends' => [ |
||
401 | ['name' => 'User B'], |
||
402 | ['name' => 'User C'], |
||
403 | ], |
||
404 | 'foes' => [ |
||
405 | ['name' => 'User D'], |
||
406 | ['name' => 'User E'], |
||
407 | ], |
||
408 | ], |
||
409 | ], |
||
410 | 'b' => [ |
||
411 | [ |
||
412 | 'name' => 'User B', |
||
413 | 'friends' => [ |
||
414 | ['name' => 'User A'], |
||
415 | ], |
||
416 | 'foes' => [ |
||
417 | ['name' => 'User C'], |
||
418 | ], |
||
419 | ], |
||
420 | ], |
||
421 | ], |
||
422 | $result['data'], |
||
423 | 'Retrieved data is correct.' |
||
424 | ); |
||
425 | } |
||
426 | |||
427 | protected function query($query, DeferredQueryBuffer $buffer) |
||
428 | { |
||
429 | $processor = new Processor(new DeferredSchema($buffer)); |
||
430 | $processor->processPayload($query, []); |
||
431 | |||
432 | return $processor->getResponseData(); |
||
433 | } |
||
434 | } |
||
435 |