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 |
||
| 8 | class ElasticsearchFunctionalTestBase extends FunctionalTest { |
||
| 9 | public static $ignoreFixtureFileFor = array(); |
||
| 10 | |||
| 11 | protected $extraDataObjects = array( |
||
| 12 | 'SearchableTestPage','FlickrPhotoTO','FlickrAuthorTO','FlickrSetTO','FlickrTagTO', |
||
| 13 | 'SearchableTestFatherPage','SearchableTestGrandFatherPage' |
||
| 14 | ); |
||
| 15 | |||
| 16 | |||
| 17 | public function setUpOnce() { |
||
| 26 | |||
| 27 | |||
| 28 | public function setUp() { |
||
|
|
|||
| 29 | |||
| 30 | echo "*************** TEST: ".$this->getName(); |
||
| 31 | |||
| 32 | $cache = SS_Cache::factory('elasticsearch'); |
||
| 33 | $cache->clean(Zend_Cache::CLEANING_MODE_ALL); |
||
| 34 | SS_Cache::set_cache_lifetime('elasticsearch', 3600, 1000); |
||
| 35 | |||
| 36 | // this needs to be called in order to create the list of searchable |
||
| 37 | // classes and fields that are available. Simulates part of a build |
||
| 38 | $classes = array('SearchableTestPage','SiteTree','Page','FlickrPhotoTO','FlickrSetTO', |
||
| 39 | 'FlickrTagTO', 'FlickrAuthorTO'); |
||
| 40 | $this->requireDefaultRecordsFrom = $classes; |
||
| 41 | |||
| 42 | // add Searchable extension where appropriate |
||
| 43 | FlickrSetTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
| 44 | FlickrPhotoTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
| 45 | FlickrTagTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
| 46 | FlickrAuthorTO::add_extension('SilverStripe\Elastica\Searchable'); |
||
| 47 | SearchableTestPage::add_extension('SilverStripe\Elastica\Searchable'); |
||
| 48 | |||
| 49 | // clear the index |
||
| 50 | $this->service = Injector::inst()->create('SilverStripe\Elastica\ElasticaService'); |
||
| 51 | $this->service->setTestMode(true); |
||
| 52 | |||
| 53 | // A previous test may have deleted the index and then failed, so check for this |
||
| 54 | if (!$this->service->getIndex()->exists()) { |
||
| 55 | $this->service->getIndex()->create(); |
||
| 56 | } |
||
| 57 | $this->service->reset(); |
||
| 58 | |||
| 59 | // FIXME - use request getVar instead? |
||
| 60 | $_GET['progress'] = 20; |
||
| 61 | // load fixtures |
||
| 62 | |||
| 63 | $orig_fixture_file = static::$fixture_file; |
||
| 64 | |||
| 65 | View Code Duplication | foreach (static::$ignoreFixtureFileFor as $testPattern) { |
|
| 66 | $pattern = '/'.$testPattern.'/'; |
||
| 67 | if (preg_match($pattern, $this->getName())) { |
||
| 68 | static::$fixture_file = null; |
||
| 69 | } |
||
| 70 | } |
||
| 71 | |||
| 72 | parent::setUp(); |
||
| 73 | static::$fixture_file = $orig_fixture_file; |
||
| 74 | |||
| 75 | $this->publishSiteTree(); |
||
| 76 | |||
| 77 | $this->service->reset(); |
||
| 78 | |||
| 79 | // index loaded fixtures |
||
| 80 | $task = new ReindexTask($this->service); |
||
| 81 | // null request is fine as no parameters used |
||
| 82 | |||
| 83 | $task->run(null); |
||
| 84 | |||
| 85 | } |
||
| 86 | |||
| 87 | |||
| 88 | private function publishSiteTree() { |
||
| 89 | foreach (SiteTree::get()->getIterator() as $page) { |
||
| 90 | // temporarily disable Elasticsearch indexing, it will be done in a batch |
||
| 91 | $page->IndexingOff = true; |
||
| 92 | |||
| 93 | $page->publish('Stage','Live'); |
||
| 94 | } |
||
| 95 | } |
||
| 96 | |||
| 97 | |||
| 98 | //---- The HTML for search results is too long to check for, so instead check just the starting text ---- |
||
| 99 | |||
| 100 | /** |
||
| 101 | *Assert that the indexth matching css node has a prefix as expected |
||
| 102 | * |
||
| 103 | * Note: characters are stripped from the content; make sure that your assertions take this into account. |
||
| 104 | * |
||
| 105 | * @param string $selector A basic CSS selector, e.g. 'li.jobs h3' |
||
| 106 | * @param array|string $expectedMatches The content of at least one of the matched tags |
||
| 107 | * @throws PHPUnit_Framework_AssertionFailedError |
||
| 108 | * @return boolean |
||
| 109 | */ |
||
| 110 | public function assertSelectorStartsWithOrEquals($selector, $index, $expectedPrefix) { |
||
| 111 | $items = $this->cssParser()->getBySelector($selector); |
||
| 112 | |||
| 113 | $ctr = 0; |
||
| 114 | foreach ($items as $item) { |
||
| 115 | $text = strip_tags($item); |
||
| 116 | $escaped = str_replace("'", "\'", $text); |
||
| 117 | $ctr++; |
||
| 118 | } |
||
| 119 | |||
| 120 | $ctr = 0; |
||
| 121 | $item = strip_tags($items[$index]); |
||
| 122 | |||
| 123 | |||
| 124 | $errorMessage = "Failed to assert that '$item' started with '$expectedPrefix'"; |
||
| 125 | $this->assertStringStartsWith($expectedPrefix, $item, $errorMessage); |
||
| 126 | |||
| 127 | return true; |
||
| 128 | } |
||
| 129 | |||
| 130 | |||
| 131 | /* |
||
| 132 | Check all the nodes matching the selector for attribute name = expected value |
||
| 133 | */ |
||
| 134 | public function assertAttributeHasExactValue($selector, $attributeName, $expectedValue) { |
||
| 140 | |||
| 141 | |||
| 142 | public function assertAttributesHaveExactValues($selector, $expectedValues) { |
||
| 153 | |||
| 154 | |||
| 155 | public function assertNumberOfNodes($selector, $expectedAmount) { |
||
| 164 | |||
| 165 | |||
| 166 | /* Collect an array of all the <ClassName>_<ID> search results, used for checking pagination */ |
||
| 167 | public function collateSearchResults() { |
||
| 177 | |||
| 178 | } |
||
| 179 |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: