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 TestRunner 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 TestRunner, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 22 | class TestRunner extends Controller { |
||
| 23 | |||
| 24 | /** @ignore */ |
||
| 25 | private static $default_reporter; |
||
| 26 | |||
| 27 | private static $url_handlers = array( |
||
|
|
|||
| 28 | '' => 'browse', |
||
| 29 | 'coverage/module/$ModuleName' => 'coverageModule', |
||
| 30 | 'coverage/suite/$SuiteName!' => 'coverageSuite', |
||
| 31 | 'coverage/$TestCase!' => 'coverageOnly', |
||
| 32 | 'coverage' => 'coverageAll', |
||
| 33 | 'cleanupdb' => 'cleanupdb', |
||
| 34 | 'module/$ModuleName' => 'module', |
||
| 35 | 'suite/$SuiteName!' => 'suite', |
||
| 36 | 'all' => 'all', |
||
| 37 | 'build' => 'build', |
||
| 38 | '$TestCase' => 'only' |
||
| 39 | ); |
||
| 40 | |||
| 41 | private static $allowed_actions = array( |
||
| 42 | 'index', |
||
| 43 | 'browse', |
||
| 44 | 'coverage', |
||
| 45 | 'coverageAll', |
||
| 46 | 'coverageModule', |
||
| 47 | 'coverageSuite', |
||
| 48 | 'coverageOnly', |
||
| 49 | 'cleanupdb', |
||
| 50 | 'module', |
||
| 51 | 'suite', |
||
| 52 | 'all', |
||
| 53 | 'build', |
||
| 54 | 'only' |
||
| 55 | ); |
||
| 56 | |||
| 57 | /** |
||
| 58 | * @var Array Blacklist certain directories for the coverage report. |
||
| 59 | * Filepaths are relative to the webroot, without leading slash. |
||
| 60 | * |
||
| 61 | * @see http://www.phpunit.de/manual/current/en/appendixes.configuration.html |
||
| 62 | * #appendixes.configuration.blacklist-whitelist |
||
| 63 | */ |
||
| 64 | static $coverage_filter_dirs = array( |
||
| 65 | '*/thirdparty', |
||
| 66 | '*/tests', |
||
| 67 | '*/lang', |
||
| 68 | ); |
||
| 69 | |||
| 70 | /** |
||
| 71 | * Override the default reporter with a custom configured subclass. |
||
| 72 | * |
||
| 73 | * @param string $reporter |
||
| 74 | */ |
||
| 75 | public static function set_reporter($reporter) { |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Pushes a class and template manifest instance that include tests onto the |
||
| 82 | * top of the loader stacks. |
||
| 83 | */ |
||
| 84 | public static function use_test_manifest() { |
||
| 109 | |||
| 110 | public function init() { |
||
| 122 | |||
| 123 | public function Link() { |
||
| 126 | |||
| 127 | /** |
||
| 128 | * Run test classes that should be run with every commit. |
||
| 129 | * Currently excludes PhpSyntaxTest |
||
| 130 | */ |
||
| 131 | View Code Duplication | public function all($request, $coverage = false) { |
|
| 147 | |||
| 148 | /** |
||
| 149 | * Run test classes that should be run before build - i.e., everything possible. |
||
| 150 | */ |
||
| 151 | View Code Duplication | public function build() { |
|
| 163 | |||
| 164 | /** |
||
| 165 | * Browse all enabled test cases in the environment |
||
| 166 | */ |
||
| 167 | public function browse() { |
||
| 195 | |||
| 196 | /** |
||
| 197 | * Run a coverage test across all modules |
||
| 198 | */ |
||
| 199 | public function coverageAll($request) { |
||
| 203 | |||
| 204 | /** |
||
| 205 | * Run only a single coverage test class or a comma-separated list of tests |
||
| 206 | */ |
||
| 207 | public function coverageOnly($request) { |
||
| 210 | |||
| 211 | /** |
||
| 212 | * Run coverage tests for one or more "modules". |
||
| 213 | * A module is generally a toplevel folder, e.g. "mysite" or "framework". |
||
| 214 | */ |
||
| 215 | public function coverageModule($request) { |
||
| 218 | |||
| 219 | public function cleanupdb() { |
||
| 222 | |||
| 223 | /** |
||
| 224 | * Run only a single test class or a comma-separated list of tests |
||
| 225 | */ |
||
| 226 | public function only($request, $coverage = false) { |
||
| 242 | |||
| 243 | /** |
||
| 244 | * Run tests for one or more "modules". |
||
| 245 | * A module is generally a toplevel folder, e.g. "mysite" or "framework". |
||
| 246 | */ |
||
| 247 | public function module($request, $coverage = false) { |
||
| 263 | |||
| 264 | /** |
||
| 265 | * Find all test classes in a directory and return an array of them. |
||
| 266 | * @param string $directory To search in |
||
| 267 | * @param array $ignore Ignore these test classes if they are found. |
||
| 268 | * @return array |
||
| 269 | */ |
||
| 270 | protected function getTestsInDirectory($directory, $ignore = array()) { |
||
| 274 | |||
| 275 | /** |
||
| 276 | * Find all test classes in a file and return an array of them. |
||
| 277 | * @param string $file To search in |
||
| 278 | * @param array $ignore Ignore these test classes if they are found. |
||
| 279 | * @return array |
||
| 280 | */ |
||
| 281 | protected function getTestsInFile($file, $ignore = array()) { |
||
| 285 | |||
| 286 | /** |
||
| 287 | * @param array $classes to search in |
||
| 288 | * @param array $ignore Ignore these test classes if they are found. |
||
| 289 | */ |
||
| 290 | protected function filterTestClasses($classes, $ignore) { |
||
| 305 | |||
| 306 | /** |
||
| 307 | * Run tests for a test suite defined in phpunit.xml |
||
| 308 | */ |
||
| 309 | public function suite($request, $coverage = false) { |
||
| 336 | |||
| 337 | /** |
||
| 338 | * Give us some sweet code coverage reports for a particular suite. |
||
| 339 | */ |
||
| 340 | public function coverageSuite($request) { |
||
| 343 | |||
| 344 | /** |
||
| 345 | * @param array $classList |
||
| 346 | * @param boolean $coverage |
||
| 347 | */ |
||
| 348 | public function runTests($classList, $coverage = false) { |
||
| 434 | |||
| 435 | public function setUp() { |
||
| 439 | |||
| 440 | public function tearDown() { |
||
| 443 | } |
||
| 444 |