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:
Complex classes like TDBMServiceTest often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use TDBMServiceTest, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
27 | class TDBMServiceTest extends TDBMAbstractServiceTest |
||
28 | { |
||
29 | public function testGetLinkBetweenInheritedTables() |
||
37 | |||
38 | public function testGetRelatedTablesByInheritance() |
||
48 | |||
49 | /** |
||
50 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
51 | * |
||
52 | * @throws TDBMException |
||
53 | */ |
||
54 | public function testGetPrimaryKeysFromIndexedPrimaryKeysException() |
||
58 | |||
59 | /** |
||
60 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
61 | * |
||
62 | * @throws TDBMException |
||
63 | */ |
||
64 | public function testGetLinkBetweenInheritedTablesExceptions() |
||
68 | |||
69 | public function testHashPrimaryKey() |
||
89 | |||
90 | public function testInsertAndUpdateAndDelete() |
||
110 | |||
111 | public function testInsertMultipleDataAtOnceInInheritance() |
||
125 | |||
126 | public function testCompleteSave() |
||
134 | |||
135 | public function testCompleteSave2() |
||
142 | |||
143 | View Code Duplication | public function testUpdatePrimaryKey() |
|
154 | |||
155 | /** |
||
156 | * @expectedException \TheCodingMachine\TDBM\TDBMInvalidOperationException |
||
157 | * |
||
158 | * @throws TDBMInvalidOperationException |
||
159 | */ |
||
160 | public function testCannotDeleteDetachedObjects() |
||
167 | |||
168 | public function testDeleteNewObject() |
||
185 | |||
186 | View Code Duplication | public function testDeleteLoadedObject() |
|
200 | |||
201 | public function testFindObjects() |
||
227 | |||
228 | public function testRawSqlFilterCountriesByUserCount() |
||
229 | { |
||
230 | $sql = <<<SQL |
||
231 | SELECT country.*, GROUP_CONCAT(users.id) AS ids |
||
232 | FROM country |
||
233 | JOIN users ON country.id= users.country_id |
||
234 | GROUP BY country.id |
||
235 | HAVING COUNT(users.id) > 1; |
||
236 | SQL; |
||
237 | /** @var Test\Dao\Bean\CountryBean[]|\Porpaginas\Result $beans */ |
||
238 | $beans = $this->tdbmService->findObjectsFromRawSql('country', $sql, [], null, Test\Dao\Bean\CountryBean::class); |
||
239 | |||
240 | $count = 0; |
||
241 | foreach ($beans as $country) { |
||
242 | $this->assertGreaterThan(1, count($country->getUsers())); |
||
243 | $count++; |
||
244 | } |
||
245 | $this->assertEquals($count, $beans->count()); |
||
246 | } |
||
247 | |||
248 | public function testRawSqlOrderCountriesByUserCount() |
||
249 | { |
||
250 | $sql = <<<SQL |
||
251 | SELECT country.*, GROUP_CONCAT(users.id) AS ids |
||
252 | FROM country |
||
253 | JOIN users ON country.id= users.country_id |
||
254 | GROUP BY country.id |
||
255 | ORDER BY COUNT(users.id); |
||
256 | SQL; |
||
257 | |||
258 | /** @var Test\Dao\Bean\CountryBean[]|\Porpaginas\Result $beans */ |
||
259 | $beans = $this->tdbmService->findObjectsFromRawSql('country', $sql, [], null, Test\Dao\Bean\CountryBean::class); |
||
260 | |||
261 | $count = 0; |
||
262 | foreach ($beans as $country) { |
||
263 | $count++; |
||
264 | } |
||
265 | $this->assertEquals($count, $beans->count()); |
||
266 | |||
267 | for ($i = 1; $i < count($beans); $i++) { |
||
268 | $this->assertLessThanOrEqual(count($beans[$i]->getUsers()), count($beans[$i - 1]->getUsers())); |
||
269 | } |
||
270 | } |
||
271 | |||
272 | public function testRawSqlOrderUsersByCustomRoleOrder() |
||
273 | { |
||
274 | $sql = <<<SQL |
||
275 | SELECT `person`.*, `contact`.*, `users`.* |
||
276 | FROM `contact` |
||
277 | JOIN `users` ON `users`.`id` = `contact`.`id` |
||
278 | JOIN `person` ON `person`.`id` = `users`.`id` |
||
279 | JOIN `users_roles` ON users.id = users_roles.user_id |
||
280 | JOIN `roles` ON roles.id = users_roles.role_id |
||
281 | GROUP BY users.id |
||
282 | ORDER BY MAX(IF(roles.name = 'Admins', 3, IF(roles.name = 'Writers', 2, IF(roles.name = 'Singers', 1, 0)))) DESC |
||
283 | SQL; |
||
284 | |||
285 | /** @var Test\Dao\Bean\UserBean[]|\Porpaginas\Result $beans */ |
||
286 | $beans = $this->tdbmService->findObjectsFromRawSql('contact', $sql, [], null, Test\Dao\Bean\UserBean::class); |
||
287 | |||
288 | function getCustomOrder(Test\Dao\Bean\UserBean $contact) { |
||
299 | |||
300 | $this->assertCount(4, $beans); |
||
301 | |||
306 | |||
307 | public function testArrayAccess() |
||
328 | |||
329 | /** |
||
330 | * @expectedException \TheCodingMachine\TDBM\TDBMInvalidOffsetException |
||
331 | * |
||
332 | * @throws TDBMInvalidOffsetException |
||
333 | */ |
||
334 | public function testArrayAccessException() |
||
340 | |||
341 | /** |
||
342 | * @expectedException \TheCodingMachine\TDBM\TDBMInvalidOffsetException |
||
343 | * |
||
344 | * @throws TDBMInvalidOffsetException |
||
345 | */ |
||
346 | public function testArrayAccessException2() |
||
352 | |||
353 | /** |
||
354 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
355 | * |
||
356 | * @throws TDBMException |
||
357 | */ |
||
358 | View Code Duplication | public function testBeanGetException() |
|
366 | |||
367 | /** |
||
368 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
369 | * |
||
370 | * @throws TDBMException |
||
371 | */ |
||
372 | View Code Duplication | public function testBeanSetException() |
|
380 | |||
381 | public function testTake() |
||
407 | |||
408 | public function testTakeInCursorMode() |
||
434 | |||
435 | public function testMap() |
||
454 | |||
455 | /** |
||
456 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
457 | * |
||
458 | * @throws TDBMException |
||
459 | */ |
||
460 | public function testUnsetException() |
||
466 | |||
467 | /** |
||
468 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
469 | * |
||
470 | * @throws TDBMException |
||
471 | */ |
||
472 | public function testSetException() |
||
478 | |||
479 | /** |
||
480 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
481 | * |
||
482 | * @throws TDBMException |
||
483 | */ |
||
484 | public function testPageUnsetException() |
||
490 | |||
491 | /** |
||
492 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
493 | * |
||
494 | * @throws TDBMException |
||
495 | */ |
||
496 | public function testPageSetException() |
||
502 | |||
503 | View Code Duplication | public function testToArray() |
|
512 | |||
513 | public function testCursorMode() |
||
543 | |||
544 | public function testSetFetchMode() |
||
560 | |||
561 | /** |
||
562 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
563 | * |
||
564 | * @throws TDBMException |
||
565 | */ |
||
566 | public function testInvalidSetFetchMode() |
||
570 | |||
571 | /** |
||
572 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
573 | * |
||
574 | * @throws TDBMException |
||
575 | */ |
||
576 | public function testCursorModeException() |
||
580 | |||
581 | /** |
||
582 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
583 | * |
||
584 | * @throws TDBMException |
||
585 | */ |
||
586 | public function testTableNameException() |
||
590 | |||
591 | public function testLinkedTableFetch() |
||
595 | |||
596 | public function testFindObject() |
||
601 | |||
602 | /** |
||
603 | * @expectedException \TheCodingMachine\TDBM\NoBeanFoundException |
||
604 | * |
||
605 | * @throws NoBeanFoundException |
||
606 | */ |
||
607 | public function testFindObjectOrFail() |
||
611 | |||
612 | /** |
||
613 | * @expectedException \TheCodingMachine\TDBM\DuplicateRowException |
||
614 | * |
||
615 | * @throws DuplicateRowException |
||
616 | */ |
||
617 | public function testFindObjectDuplicateRow() |
||
621 | |||
622 | View Code Duplication | public function testFindObjectsByBean() |
|
630 | |||
631 | /** |
||
632 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
633 | * |
||
634 | * @throws TDBMException |
||
635 | * @throws TDBMInvalidOperationException |
||
636 | */ |
||
637 | public function testBeanWithoutStatus() |
||
647 | |||
648 | public function testFindObjectsFromSql() |
||
655 | |||
656 | /** |
||
657 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
658 | * |
||
659 | * @throws TDBMException |
||
660 | */ |
||
661 | public function testFindObjectsFromSqlBadTableName() |
||
666 | |||
667 | /** |
||
668 | * @expectedException \TheCodingMachine\TDBM\TDBMException |
||
669 | * |
||
670 | * @throws TDBMException |
||
671 | */ |
||
672 | public function testFindObjectsFromSqlGroupBy() |
||
678 | |||
679 | public function testFindObjectFromSql() |
||
685 | |||
686 | /** |
||
687 | * @expectedException \TheCodingMachine\TDBM\DuplicateRowException |
||
688 | * |
||
689 | * @throws DuplicateRowException |
||
690 | */ |
||
691 | public function testFindObjectFromSqlException() |
||
696 | |||
697 | View Code Duplication | public function testFindObjectsFromSqlHierarchyDown() |
|
704 | |||
705 | View Code Duplication | public function testFindObjectsFromSqlHierarchyUp() |
|
712 | |||
713 | public function testLogger() |
||
724 | |||
725 | public function testFindObjectsCountWithOneToManyLink() |
||
731 | |||
732 | public function testFindObjectsFromSqlCountWithOneToManyLink() |
||
738 | |||
739 | /* |
||
740 | public function testObjectAsFilter() { |
||
741 | $dpt = $this->tdbmService->getObject('departements', 1); |
||
742 | $dpt2 = $this->tdbmService->getObject('departements', $dpt); |
||
743 | $this->assertEquals($dpt, $dpt2); |
||
744 | } |
||
745 | |||
746 | public function testOneWayAndTheOpposite() { |
||
747 | $this->tdbmService->getObjects('utilisateur_entite', new EqualFilter('entites', 'appellation', 'foo')); |
||
748 | $this->tdbmService->getObjects('entites', new EqualFilter('utilisateur_entite', 'id_utilisateur', '1')); |
||
749 | } |
||
750 | |||
751 | public function testOneWayAndTheOpposite2() { |
||
752 | $this->tdbmService->getObjects('utilisateur_entite', new EqualFilter('departements', 'id', '1')); |
||
753 | $this->tdbmService->getObjects('departements', new EqualFilter('utilisateur_entite', 'id_utilisateur', '1')); |
||
754 | } |
||
755 | |||
756 | public function testOneWayAndTheOpposite3() { |
||
757 | $this->tdbmService->getObjects('utilisateur_entite', |
||
758 | [ |
||
759 | new EqualFilter('entites', 'appellation', 1), |
||
760 | ] |
||
761 | ); |
||
762 | $this->tdbmService->getObjects('entites', [ |
||
763 | new EqualFilter('departements', 'id', 1), |
||
764 | new EqualFilter('utilisateur_entite', 'id_utilisateur', '1'), |
||
765 | ] |
||
766 | ); |
||
767 | } |
||
768 | |||
769 | public function testOneWayAndTheOpposite4() { |
||
770 | $this->tdbmService->getObjects('utilisateur_entite', null, |
||
771 | [ |
||
772 | new OrderByColumn('entites', 'appellation', 'ASC'), |
||
773 | ] |
||
774 | ); |
||
775 | $this->tdbmService->getObjects('entites', new EqualFilter('utilisateur_entite', 'id_utilisateur', '1'), |
||
776 | [ |
||
777 | new OrderByColumn('departements', 'id', 'ASC') |
||
778 | ] |
||
779 | ); |
||
780 | } |
||
781 | |||
782 | public function testTDBMObjectArrayMultipleForeach() { |
||
783 | $results = $this->tdbmService->getObjects('departements'); |
||
784 | $this->assertTrue(is_array($results)); |
||
785 | $count = 0; |
||
786 | foreach ($results as $result) { |
||
787 | $count++; |
||
788 | } |
||
789 | $this->assertEquals(95, $count); |
||
790 | |||
791 | $count = 0; |
||
792 | foreach ($results as $result) { |
||
793 | $count++; |
||
794 | } |
||
795 | $this->assertEquals(95, $count); |
||
796 | |||
797 | } |
||
798 | |||
799 | public function testTDBMObjectsCursorMode() { |
||
800 | $this->tdbmService->setFetchMode(TDBMService::MODE_CURSOR); |
||
801 | $results = $this->tdbmService->getObjects('departements'); |
||
802 | |||
803 | $count = 0; |
||
804 | foreach ($results as $result) { |
||
805 | $count++; |
||
806 | } |
||
807 | $this->assertEquals(95, $count); |
||
808 | } |
||
809 | |||
810 | public function testTDBMObjectCursorMode() { |
||
811 | $this->tdbmService->setFetchMode(TDBMService::MODE_CURSOR); |
||
812 | $result = $this->tdbmService->getObject('departements', array(new EqualFilter('departements', 'id', 1))); |
||
813 | |||
814 | $this->assertEquals("Ain", $result->nom); |
||
815 | } |
||
816 | |||
817 | |||
818 | public function testTDBMObjectArrayCount() { |
||
819 | $results = $this->tdbmService->getObjects('departements'); |
||
820 | $this->assertEquals(95, count($results)); |
||
821 | $this->assertEquals(95, count($results)); |
||
822 | |||
823 | } |
||
824 | |||
825 | |||
826 | public function testTDBMObjectArrayAccessByKey() { |
||
827 | $results = $this->tdbmService->getObjects('departements'); |
||
828 | |||
829 | $this->assertEquals("Alpes Maritimes", $results[5]->nom); |
||
830 | } |
||
831 | |||
832 | public function testTDBMObjectArrayCountAfterForeach() { |
||
833 | $results = $this->tdbmService->getObjects('departements'); |
||
834 | foreach ($results as $result) { |
||
835 | // Do nothing |
||
836 | } |
||
837 | $this->assertEquals(95, count($results)); |
||
838 | } |
||
839 | |||
840 | public function testStorage() { |
||
841 | $results = $this->tdbmService->getObjects('departements'); |
||
842 | |||
843 | $result = $this->tdbmService->getObject('departements', 1); |
||
844 | |||
845 | $this->assertTrue($results[0] === $result); |
||
846 | } |
||
847 | |||
848 | public function testCloneTDBMObject() |
||
849 | { |
||
850 | // Create a new object |
||
851 | $object = $this->tdbmService->getNewObject('departements'); |
||
852 | $object->id_region = 22; |
||
853 | $object->numero = '100'; |
||
854 | $object->nom = 'test'; |
||
855 | $object->nom_web = 'test'; |
||
856 | // Save the object |
||
857 | $object->save(); |
||
858 | |||
859 | // Try to clone the object |
||
860 | $cloneObject = clone $object; |
||
861 | // Save the cloned object |
||
862 | $cloneObject->save(); |
||
863 | |||
864 | $this->assertNotEquals($object->id, $cloneObject->id); |
||
865 | $this->assertEquals($object->nom, $cloneObject->nom); |
||
866 | |||
867 | $this->tdbmService->deleteObject($object); |
||
868 | $this->tdbmService->deleteObject($cloneObject); |
||
869 | } |
||
870 | */ |
||
871 | } |
||
872 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.