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 ResourceTest 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 ResourceTest, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | final class ResourceTest extends PHPUnit_Framework_TestCase |
||
32 | { |
||
33 | /** |
||
34 | * @expectedException \Sensorario\Resources\Exceptions\UndefinedMethodException |
||
35 | * @expectedExceptionMessageRegExp #Method `.*::.*()` is not yet implemented# |
||
36 | */ |
||
37 | public function testExceptionIsThrownWhenNotYetImplementedMethodIsCalled() |
||
46 | |||
47 | /** |
||
48 | * @expectedException Sensorario\Resources\Exceptions\NotAllowedKeyException |
||
49 | * @expectedExceptionMessageRegExp #Key `.*::.*` is not allowed# |
||
50 | */ |
||
51 | public function testNotAllowedFieldThroghRuntimeException() |
||
59 | |||
60 | /** |
||
61 | * @expectedException Sensorario\Resources\Exceptions\PropertyException |
||
62 | * @expectedExceptionMessageRegExp #Property `.*::.*` is mandatory but not set# |
||
63 | */ |
||
64 | public function testMissingMandatoryFieldThroghRuntimeException() |
||
68 | |||
69 | public function testMandatoryFieldsAreAuthomaticallyAllowed() |
||
76 | |||
77 | View Code Duplication | public function testResourcesHasMagicMethod() |
|
89 | |||
90 | /** |
||
91 | * @expectedException Sensorario\Resources\Exceptions\PropertyNameEmptyException |
||
92 | * @expectedExceptionMessage Oops! Property name requested is empty string!! |
||
93 | */ |
||
94 | View Code Duplication | public function testExceptionMessageInCaseOfEmptyPropertyName() |
|
106 | |||
107 | /** |
||
108 | * @expectedException Sensorario\Resources\Exceptions\FactoryMethodException |
||
109 | * @expectedExceptionMessageRegExp #Invalid factory method# |
||
110 | */ |
||
111 | public function testFactoryMethods() |
||
115 | |||
116 | public function testCanHaveDefaultValues() |
||
125 | |||
126 | public function testPropertyExists() |
||
134 | |||
135 | /** @dataProvider propertiesProvider */ |
||
136 | public function testHasProperties($result, $properties) |
||
148 | |||
149 | public function propertiesProvider() |
||
156 | |||
157 | public function testAllowAccessToProperties() |
||
168 | |||
169 | public function testAllowAccessToPropertiesThroughDefaultValue() |
||
178 | |||
179 | /** |
||
180 | * @expectedException Sensorario\Resources\Exceptions\NoValuesException |
||
181 | */ |
||
182 | public function testThroughExceptionWhenNoValuesProvided() |
||
187 | |||
188 | /** |
||
189 | * @expectedException Sensorario\Resources\Exceptions\AttributeTypeException |
||
190 | * @expectedExceptionMessageRegExp #Attribute `.*` must be of type `array`# |
||
191 | */ |
||
192 | public function testPropertyCouldBeAScalar() |
||
198 | |||
199 | /** |
||
200 | * @expectedException Sensorario\Resources\Exceptions\NotObjectTypeFoundException |
||
201 | * @expectedExceptionMessageRegExp #Attribute `.*` must be an object of type DateTime# |
||
202 | */ |
||
203 | public function testPropertyCouldBeTheRightnObject() |
||
209 | |||
210 | public function testPropertiesAccessor() |
||
222 | |||
223 | /** |
||
224 | * @expectedException Sensorario\Resources\Exceptions\PropertyNotSetException |
||
225 | * @expectedExceptionMessageRegExp #Property `.*::.*` is mandatory but not set# |
||
226 | */ |
||
227 | public function testWhenCondition() |
||
234 | |||
235 | public function testShouldNotFail() |
||
241 | |||
242 | public function testResourcesComposition() |
||
258 | |||
259 | /** |
||
260 | * @expectedException Sensorario\Resources\Exceptions\PropertyException |
||
261 | * @expectedExceptionMessageRegExp #When property `.*` has value `.*` also `.*` is mandatory# |
||
262 | */ |
||
263 | public function testMandatoryValuesWhenPropertyAssumeAValue() |
||
269 | |||
270 | public function test() |
||
277 | |||
278 | /** |
||
279 | * @expectedException Sensorario\Resources\Exceptions\PropertyWithoutRuleException |
||
280 | * @expectedExceptionMessageRegExp #When property `.*` is an object class, must be defined in Resources::rules()# |
||
281 | */ |
||
282 | public function testAnExceptionIsThrownIfAPropertyIsAnObjectButClassInNotDefinedInRuleMethod() |
||
288 | |||
289 | public function testDefaultValuesTwo() |
||
321 | |||
322 | public function testDefaultValues() |
||
352 | |||
353 | public function testResourceShouldBeCreatedViaContainer() |
||
375 | |||
376 | /** |
||
377 | * @expectedException Sensorario\Resources\Exceptions\PropertyNotSetException |
||
378 | * @expectedExceptionMessageRegExp #Property `.*::.*` is mandatory but not set# |
||
379 | */ |
||
380 | View Code Duplication | public function testDependentMandatoryProperties() |
|
416 | |||
417 | View Code Duplication | public function testMandatoryConstraintsAreAutomaticallyAllowed() |
|
434 | |||
435 | public function testPropertyType() |
||
457 | |||
458 | /** |
||
459 | * @expectedException Sensorario\Resources\Exceptions\UnexpectedValueException |
||
460 | * @expectedExceptionMessageRegExp #Value `.*` is not allowed for key `.*`. Allowed values are:# |
||
461 | */ |
||
462 | View Code Duplication | public function testAllowedValues() |
|
490 | |||
491 | public function testRewriteRulesWithCondition() |
||
543 | |||
544 | /** |
||
545 | * @expectedException Sensorario\Resources\Exceptions\OutOfRangeException |
||
546 | * @expectedExceptionMessageRegExp #Value `.*` is out of range: `.*`.# |
||
547 | */ |
||
548 | View Code Duplication | public function testAcceptRangeOfValues() |
|
576 | |||
577 | public function testAllResourcesInheritGlobalAllowingConfiguration() |
||
617 | |||
618 | /** |
||
619 | * @expectedException Sensorario\Resources\Exceptions\PropertyException |
||
620 | */ |
||
621 | View Code Duplication | public function testHasMandatoryPropertiesWhenAnotherOneHasAParticularValue() |
|
656 | |||
657 | /** |
||
658 | * @expectedException Sensorario\Resources\Exceptions\EmailException |
||
659 | */ |
||
660 | public function testEmailValidationFails() |
||
686 | |||
687 | /** |
||
688 | * @expectedException Sensorario\Resources\Exceptions\WrongPropertyValueException |
||
689 | * @expectedExceptionMessageRegExp #Property .* must be an integer!# |
||
690 | */ |
||
691 | public function testIntegersCanBeDefinedWithNumberRule() |
||
713 | |||
714 | public function testEmailValidation() |
||
745 | |||
746 | /** @dataProvider rules */ |
||
747 | View Code Duplication | public function testRulesKnowsIfRuleIsDefinedOrNot($expectation, $ruleName) |
|
778 | |||
779 | public function rules() |
||
786 | |||
787 | View Code Duplication | public function testProvideRule() |
|
820 | |||
821 | /** |
||
822 | * @expectedException Sensorario\Resources\Exceptions\PropertyWithoutRuleException |
||
823 | * @expectedExceptionMessage Property date is an object but is not defined in rules |
||
824 | */ |
||
825 | public function testUndefinedObject() |
||
831 | } |
||
832 |
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.