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 AgaviTesting 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 AgaviTesting, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
39 | class AgaviTesting |
||
40 | { |
||
41 | /** |
||
42 | * @var PHP_CodeCoverage_Filter The code coverage filter for our tests. |
||
43 | */ |
||
44 | public static $codeCoverageFilter = null; |
||
45 | |||
46 | /** |
||
47 | * Get the code coverage filter instance we will use for tests. |
||
48 | * When running PHPUnit 3.5, this will return the singleton instance. |
||
49 | * When running PHPUnit 3.6, this will return the instance we hold internally; |
||
50 | * this same instance will be passed to PHPUnit in AgaviTesting::dispatch(). |
||
51 | * |
||
52 | * @return PHP_CodeCoverage_Filter The code coverage filter for our tests. |
||
53 | * |
||
54 | * @author David Zülke <[email protected]> |
||
55 | * @since 1.0.7 |
||
56 | * @deprecated 1.1.0 Use PhpUnitCli |
||
57 | */ |
||
58 | public static function getCodeCoverageFilter() |
||
59 | { |
||
60 | if (self::$codeCoverageFilter === null) { |
||
61 | // PHP_CodeCoverage doesn't expose any version info, we'll have to check if there is a static getInstance method |
||
62 | self::$codeCoverageFilter = method_exists('PHP_CodeCoverage_Filter', 'getInstance') ? PHP_CodeCoverage_Filter::getInstance() : new PHP_CodeCoverage_Filter(); |
||
63 | } |
||
64 | |||
65 | return self::$codeCoverageFilter; |
||
66 | } |
||
67 | |||
68 | /** |
||
69 | * Startup the Agavi core |
||
70 | * |
||
71 | * @param string $environment environment the environment to use for this session. |
||
72 | * |
||
73 | * @author Felix Gilcher <[email protected]> |
||
74 | * @since 1.0.0 |
||
75 | * @deprecated 1.1.0 Use PhpUnitCli |
||
76 | */ |
||
77 | public static function bootstrap($environment = null) |
||
78 | { |
||
79 | PhpUnitCli::bootstrap($environment); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * Dispatch the test run. |
||
84 | * |
||
85 | * @param array $arguments An array of arguments configuring PHPUnit behavior. |
||
86 | * @param bool $exit Whether exit() should be called with an appropriate shell |
||
87 | * exit status to indicate success or failures/errors. |
||
88 | * |
||
89 | * @return \PHPUnit_Framework_TestResult The PHPUnit result object. |
||
90 | * |
||
91 | * @author Felix Gilcher <[email protected]> |
||
92 | * @author David Zülke <[email protected]> |
||
93 | * @since 1.0.0 |
||
94 | * @deprecated 1.1.0 Use PhpUnitCli |
||
95 | */ |
||
96 | public static function dispatch($arguments = array(), $exit = true) |
||
97 | { |
||
98 | |||
99 | $suites = include ConfigCache::checkConfig(Config::get('core.testing_dir').'/config/suites.xml'); |
||
100 | $master_suite = new TestSuite('Master'); |
||
101 | |||
102 | if (!empty($arguments['include-suite'])) { |
||
103 | $names = explode(',', $arguments['include-suite']); |
||
104 | unset($arguments['include-suite']); |
||
105 | |||
106 | View Code Duplication | foreach ($names as $name) { |
|
|
|||
107 | if (empty($suites[$name])) { |
||
108 | throw new \InvalidArgumentException(sprintf('Invalid suite name %1$s.', $name)); |
||
109 | } |
||
110 | |||
111 | $master_suite->addTest(self::createSuite($name, $suites[$name])); |
||
112 | } |
||
113 | } else { |
||
114 | $excludes = array(); |
||
115 | if (!empty($arguments['exclude-suite'])) { |
||
116 | $excludes = explode(',', $arguments['exclude-suite']); |
||
117 | unset($arguments['exclude-suite']); |
||
118 | } |
||
119 | foreach ($suites as $name => $suite) { |
||
120 | if (!in_array($name, $excludes)) { |
||
121 | $master_suite->addTest(self::createSuite($name, $suite)); |
||
122 | } |
||
123 | } |
||
124 | } |
||
125 | |||
126 | if (version_compare(\PHPUnit_Runner_Version::id(), '3.6', '<')) { |
||
127 | // PHP_CodeCoverage_Filter is a singleton |
||
128 | $runner = new \PHPUnit_TextUI_TestRunner(); |
||
129 | } else { |
||
130 | // PHP_CodeCoverage_Filter instance must be passed to the test runner |
||
131 | $runner = new \PHPUnit_TextUI_TestRunner(null, self::$codeCoverageFilter); |
||
132 | } |
||
133 | $result = $runner->doRun($master_suite, $arguments); |
||
134 | if ($exit) { |
||
135 | // bai |
||
136 | exit(self::getExitStatus($result)); |
||
137 | } else { |
||
138 | // return result so calling code can use it |
||
139 | return $result; |
||
140 | } |
||
141 | } |
||
142 | |||
143 | /** |
||
144 | * Compute a shell exit status for the given result. |
||
145 | * Behaves like PHPUnit_TextUI_Command. |
||
146 | * |
||
147 | * @param PHPUnit_Framework_TestResult The test result object. |
||
148 | * |
||
149 | * @return int The shell exit code. |
||
150 | * @deprecated 1.1.0 Use PhpUnitCli |
||
151 | */ |
||
152 | public static function getExitStatus(\PHPUnit_Framework_TestResult $result) |
||
162 | |||
163 | /** |
||
164 | * Initialize a suite from the given instructions and add registered tests. |
||
165 | * |
||
166 | * @param string Name of the suite |
||
167 | * @param array An array containing information about the suite |
||
168 | * |
||
169 | * @return TestSuite The initialized test suite object. |
||
170 | * |
||
171 | * @author Felix Gilcher <[email protected]> |
||
172 | * @since 1.0.0 |
||
173 | * @deprecated 1.1.0 Use PhpUnitCli |
||
174 | */ |
||
175 | protected static function createSuite($name, array $suite) |
||
204 | |||
205 | /** |
||
206 | * Handles the commandline arguments passed. |
||
207 | * |
||
208 | * @return array the commandline arguments |
||
209 | * |
||
210 | * @author Felix Gilcher <[email protected]> |
||
211 | * @since 1.0.0 |
||
212 | * @deprecated 1.1.0 Use PhpUnitCli |
||
213 | */ |
||
214 | public static function processCommandlineOptions() |
||
326 | |||
327 | /** |
||
328 | * Checks whether all dependencies for writing code coverage information |
||
329 | * are met. |
||
330 | * |
||
331 | * @return true if all deps are met |
||
332 | * @throws AgaviException if a dependency is missing |
||
333 | * |
||
334 | * @author Felix Gilcher <[email protected]> |
||
335 | * @since 1.0.0 |
||
336 | * @deprecated 1.1.0 Use PhpUnitCli |
||
337 | */ |
||
338 | protected static function checkCodeCoverageDeps() |
||
352 | |||
353 | /** |
||
354 | * shows the help for the commandline call |
||
355 | * |
||
356 | * @author Felix Gilcher <[email protected]> |
||
357 | * @since 1.0.0 |
||
358 | * @deprecated 1.1.0 Use PhpUnitCli |
||
359 | */ |
||
360 | protected static function showHelp() |
||
390 | } |
||
391 |
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.