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 TopHitsTest 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 TopHitsTest, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | class TopHitsTest extends BaseAggregationTest |
||
| 20 | { |
||
| 21 | /** |
||
| 22 | * @group unit |
||
| 23 | */ |
||
| 24 | public function testSetSize(): void |
||
| 25 | { |
||
| 26 | $agg = new TopHits('agg_name'); |
||
| 27 | $returnValue = $agg->setSize(12); |
||
| 28 | $this->assertEquals(12, $agg->getParam('size')); |
||
| 29 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 30 | } |
||
| 31 | |||
| 32 | /** |
||
| 33 | * @group unit |
||
| 34 | */ |
||
| 35 | View Code Duplication | public function testSetFrom(): void |
|
|
|
|||
| 36 | { |
||
| 37 | $agg = new TopHits('agg_name'); |
||
| 38 | $returnValue = $agg->setFrom(12); |
||
| 39 | $this->assertEquals(12, $agg->getParam('from')); |
||
| 40 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 41 | } |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @group unit |
||
| 45 | */ |
||
| 46 | public function testSetSort(): void |
||
| 47 | { |
||
| 48 | $sort = ['last_activity_date' => ['order' => 'desc']]; |
||
| 49 | $agg = new TopHits('agg_name'); |
||
| 50 | $returnValue = $agg->setSort($sort); |
||
| 51 | $this->assertEquals($sort, $agg->getParam('sort')); |
||
| 52 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 53 | } |
||
| 54 | |||
| 55 | /** |
||
| 56 | * @group unit |
||
| 57 | */ |
||
| 58 | View Code Duplication | public function testSetSource(): void |
|
| 59 | { |
||
| 60 | $fields = ['title', 'tags']; |
||
| 61 | $agg = new TopHits('agg_name'); |
||
| 62 | $returnValue = $agg->setSource($fields); |
||
| 63 | $this->assertEquals($fields, $agg->getParam('_source')); |
||
| 64 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 65 | } |
||
| 66 | |||
| 67 | /** |
||
| 68 | * @group unit |
||
| 69 | */ |
||
| 70 | View Code Duplication | public function testSetVersion(): void |
|
| 71 | { |
||
| 72 | $agg = new TopHits('agg_name'); |
||
| 73 | $returnValue = $agg->setVersion(true); |
||
| 74 | $this->assertTrue($agg->getParam('version')); |
||
| 75 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 76 | |||
| 77 | $agg->setVersion(false); |
||
| 78 | $this->assertFalse($agg->getParam('version')); |
||
| 79 | } |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @group unit |
||
| 83 | */ |
||
| 84 | View Code Duplication | public function testSetExplain(): void |
|
| 85 | { |
||
| 86 | $agg = new TopHits('agg_name'); |
||
| 87 | $returnValue = $agg->setExplain(true); |
||
| 88 | $this->assertTrue($agg->getParam('explain')); |
||
| 89 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 90 | |||
| 91 | $agg->setExplain(false); |
||
| 92 | $this->assertFalse($agg->getParam('explain')); |
||
| 93 | } |
||
| 94 | |||
| 95 | /** |
||
| 96 | * @group unit |
||
| 97 | */ |
||
| 98 | public function testSetHighlight(): void |
||
| 99 | { |
||
| 100 | $highlight = [ |
||
| 101 | 'fields' => [ |
||
| 102 | 'title', |
||
| 103 | ], |
||
| 104 | ]; |
||
| 105 | $agg = new TopHits('agg_name'); |
||
| 106 | $returnValue = $agg->setHighlight($highlight); |
||
| 107 | $this->assertEquals($highlight, $agg->getParam('highlight')); |
||
| 108 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 109 | } |
||
| 110 | |||
| 111 | /** |
||
| 112 | * @group unit |
||
| 113 | */ |
||
| 114 | View Code Duplication | public function testSetFieldDataFields(): void |
|
| 115 | { |
||
| 116 | $fields = ['title', 'tags']; |
||
| 117 | $agg = new TopHits('agg_name'); |
||
| 118 | $returnValue = $agg->setFieldDataFields($fields); |
||
| 119 | $this->assertEquals($fields, $agg->getParam('docvalue_fields')); |
||
| 120 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 121 | } |
||
| 122 | |||
| 123 | /** |
||
| 124 | * @group unit |
||
| 125 | */ |
||
| 126 | public function testSetScriptFields(): void |
||
| 127 | { |
||
| 128 | $script = new Script('1 + 2'); |
||
| 129 | $scriptFields = new ScriptFields(['three' => $script]); |
||
| 130 | |||
| 131 | $agg = new TopHits('agg_name'); |
||
| 132 | $returnValue = $agg->setScriptFields($scriptFields); |
||
| 133 | $this->assertEquals($scriptFields->toArray(), $agg->getParam('script_fields')->toArray()); |
||
| 134 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 135 | } |
||
| 136 | |||
| 137 | /** |
||
| 138 | * @group unit |
||
| 139 | */ |
||
| 140 | public function testAddScriptField(): void |
||
| 141 | { |
||
| 142 | $script = new Script('2+3'); |
||
| 143 | $agg = new TopHits('agg_name'); |
||
| 144 | $returnValue = $agg->addScriptField('five', $script); |
||
| 145 | $this->assertEquals(['five' => $script->toArray()], $agg->getParam('script_fields')->toArray()); |
||
| 146 | $this->assertInstanceOf(TopHits::class, $returnValue); |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * @group functional |
||
| 151 | */ |
||
| 152 | View Code Duplication | public function testAggregateUpdatedRecently(): void |
|
| 153 | { |
||
| 154 | $aggr = new TopHits('top_tag_hits'); |
||
| 155 | $aggr->setSize(1); |
||
| 156 | $aggr->setSort(['last_activity_date' => ['order' => 'desc']]); |
||
| 157 | |||
| 158 | $resultDocs = []; |
||
| 159 | $outerAggrResult = $this->getOuterAggregationResult($aggr); |
||
| 160 | foreach ($outerAggrResult['buckets'] as $bucket) { |
||
| 161 | foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) { |
||
| 162 | $resultDocs[] = $doc['_id']; |
||
| 163 | } |
||
| 164 | } |
||
| 165 | $this->assertEquals([1, 3], $resultDocs); |
||
| 166 | } |
||
| 167 | |||
| 168 | /** |
||
| 169 | * @group functional |
||
| 170 | */ |
||
| 171 | View Code Duplication | public function testAggregateUpdatedFarAgo(): void |
|
| 172 | { |
||
| 173 | $aggr = new TopHits('top_tag_hits'); |
||
| 174 | $aggr->setSize(1); |
||
| 175 | $aggr->setSort(['last_activity_date' => ['order' => 'asc']]); |
||
| 176 | |||
| 177 | $resultDocs = []; |
||
| 178 | $outerAggrResult = $this->getOuterAggregationResult($aggr); |
||
| 179 | foreach ($outerAggrResult['buckets'] as $bucket) { |
||
| 180 | foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) { |
||
| 181 | $resultDocs[] = $doc['_id']; |
||
| 182 | } |
||
| 183 | } |
||
| 184 | $this->assertEquals([2, 4], $resultDocs); |
||
| 185 | } |
||
| 186 | |||
| 187 | /** |
||
| 188 | * @group functional |
||
| 189 | */ |
||
| 190 | View Code Duplication | public function testAggregateTwoDocumentPerTag(): void |
|
| 191 | { |
||
| 192 | $aggr = new TopHits('top_tag_hits'); |
||
| 193 | $aggr->setSize(2); |
||
| 194 | |||
| 195 | $resultDocs = []; |
||
| 196 | $outerAggrResult = $this->getOuterAggregationResult($aggr); |
||
| 197 | foreach ($outerAggrResult['buckets'] as $bucket) { |
||
| 198 | foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) { |
||
| 199 | $resultDocs[] = $doc['_id']; |
||
| 200 | } |
||
| 201 | } |
||
| 202 | $this->assertEquals([1, 2, 3, 4], $resultDocs); |
||
| 203 | } |
||
| 204 | |||
| 205 | /** |
||
| 206 | * @group functional |
||
| 207 | */ |
||
| 208 | View Code Duplication | public function testAggregateTwoDocumentPerTagWithOffset(): void |
|
| 209 | { |
||
| 210 | $aggr = new TopHits('top_tag_hits'); |
||
| 211 | $aggr->setSize(2); |
||
| 212 | $aggr->setFrom(1); |
||
| 213 | $aggr->setSort(['last_activity_date' => ['order' => 'desc']]); |
||
| 214 | |||
| 215 | $resultDocs = []; |
||
| 216 | $outerAggrResult = $this->getOuterAggregationResult($aggr); |
||
| 217 | foreach ($outerAggrResult['buckets'] as $bucket) { |
||
| 218 | foreach ($bucket['top_tag_hits']['hits']['hits'] as $doc) { |
||
| 219 | $resultDocs[] = $doc['_id']; |
||
| 220 | } |
||
| 221 | } |
||
| 222 | $this->assertEquals([2, 4], $resultDocs); |
||
| 223 | } |
||
| 224 | |||
| 225 | public function limitedSourceProvider() |
||
| 232 | |||
| 233 | /** |
||
| 234 | * @group functional |
||
| 235 | * @dataProvider limitedSourceProvider |
||
| 236 | * |
||
| 237 | * @param mixed $source |
||
| 238 | */ |
||
| 239 | public function testAggregateWithLimitedSource($source): void |
||
| 240 | { |
||
| 241 | $aggr = new TopHits('top_tag_hits'); |
||
| 242 | $aggr->setSource($source); |
||
| 243 | |||
| 244 | $resultDocs = []; |
||
| 245 | $outerAggrResult = $this->getOuterAggregationResult($aggr); |
||
| 246 | foreach ($outerAggrResult['buckets'] as $bucket) { |
||
| 254 | |||
| 255 | /** |
||
| 256 | * @group functional |
||
| 257 | */ |
||
| 258 | View Code Duplication | public function testAggregateWithVersion(): void |
|
| 271 | |||
| 272 | /** |
||
| 273 | * @group functional |
||
| 274 | */ |
||
| 275 | View Code Duplication | public function testAggregateWithExplain(): void |
|
| 288 | |||
| 289 | /** |
||
| 290 | * @group functional |
||
| 291 | */ |
||
| 292 | public function testAggregateWithScriptFields(): void |
||
| 308 | |||
| 309 | /** |
||
| 310 | * @group functional |
||
| 311 | */ |
||
| 312 | public function testAggregateWithHighlight(): void |
||
| 330 | |||
| 331 | /** |
||
| 332 | * @group functional |
||
| 333 | */ |
||
| 334 | public function testAggregateWithFieldData(): void |
||
| 352 | |||
| 353 | protected function _getIndexForTest(): Index |
||
| 400 | |||
| 401 | View Code Duplication | protected function getOuterAggregationResult($innerAggr) |
|
| 413 | } |
||
| 414 |
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.