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 |
||
15 | class ClientTest extends \PHPUnit_Framework_TestCase |
||
16 | { |
||
17 | use InvokeInaccessibleMethodTrait; |
||
18 | |||
19 | /** |
||
20 | * @return Client |
||
21 | */ |
||
22 | private function getClient() |
||
26 | |||
27 | /** |
||
28 | * @param int $responseCode |
||
29 | * @param null|array $headers |
||
30 | * @param array $responseBody |
||
31 | * @param callable|null $expectationCallback |
||
32 | * |
||
33 | * @return Client |
||
34 | */ |
||
35 | private function getClientWithResponse( |
||
36 | $responseCode = 200, |
||
37 | $headers = [], |
||
38 | $responseBody = [], |
||
39 | $expectationCallback = null |
||
40 | ) { |
||
41 | $stream = Stream::factory(json_encode($responseBody)); |
||
42 | $validResponse = new Response($responseCode, $headers, $stream); |
||
|
|||
43 | |||
44 | $guzzleClient = $this->getMock(GuzzleHttpClient::class, ['send', 'createRequest']); |
||
45 | $guzzleClient->expects($this->once()) |
||
46 | ->method('send') |
||
47 | ->willReturn($validResponse); |
||
48 | |||
49 | if ($expectationCallback) { |
||
50 | call_user_func($expectationCallback, $guzzleClient); |
||
51 | } |
||
52 | |||
53 | $client = $this->getClient(); |
||
54 | $client->setClient($guzzleClient); |
||
55 | |||
56 | return $client; |
||
57 | } |
||
58 | |||
59 | public function testConstructor() |
||
60 | { |
||
61 | $client = $this->getClient(); |
||
62 | |||
63 | $this->assertEquals('http://api.snd.no/news/v2', $client->getApiUrl()); |
||
64 | $this->assertEquals('key', $client->getApiKey()); |
||
65 | $this->assertEquals('secret', $client->getApiSecret()); |
||
66 | $this->assertEquals('sa', $client->getPublicationId()); |
||
67 | } |
||
68 | |||
69 | public function testApiGet() |
||
70 | { |
||
71 | $client = $this->getClientWithResponse(200, [], [], function (GuzzleHttpClient $guzzleClient) { |
||
72 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
73 | $guzzleClient->expects($this->once()) |
||
74 | ->method('createRequest') |
||
75 | ->with( |
||
76 | 'GET', |
||
77 | 'http://api.snd.no/news/v2/' |
||
78 | ) |
||
79 | ->willReturn(new Request('GET', '/')); |
||
80 | }); |
||
81 | |||
82 | $this->invokeMethod($client, 'apiGet', ['/']); |
||
83 | } |
||
84 | |||
85 | /** |
||
86 | * @expectedException \Stp\SndApi\Common\Exception\UnsatisfactoryResponseCodeException |
||
87 | */ |
||
88 | public function testApiGetWith301Response() |
||
89 | { |
||
90 | $client = $this->getClientWithResponse(301, [], [], function (GuzzleHttpClient $guzzleClient) { |
||
91 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
92 | $guzzleClient->expects($this->once()) |
||
93 | ->method('createRequest') |
||
94 | ->with( |
||
95 | 'GET', |
||
96 | 'http://api.snd.no/news/v2/' |
||
97 | ) |
||
98 | ->willReturn(new Request('GET', '/')); |
||
99 | }); |
||
100 | |||
101 | $client->getServiceDocument(); |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * @expectedException \Stp\SndApi\Common\Exception\ItemDoesNotExistsException |
||
106 | */ |
||
107 | public function testApiGetWith404Response() |
||
108 | { |
||
109 | $client = $this->getClientWithResponse(404, [], [], function (GuzzleHttpClient $guzzleClient) { |
||
110 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
111 | $guzzleClient->expects($this->once()) |
||
112 | ->method('createRequest') |
||
113 | ->with( |
||
114 | 'GET', |
||
115 | 'http://api.snd.no/news/v2/' |
||
116 | ) |
||
117 | ->willReturn(new Request('GET', '/')); |
||
118 | }); |
||
119 | |||
120 | $client->getServiceDocument(); |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * @expectedException \Stp\SndApi\Common\Exception\UnsatisfactoryResponseCodeException |
||
125 | */ |
||
126 | public function testApiGetWith403Response() |
||
127 | { |
||
128 | $client = $this->getClientWithResponse(403, [], [], function (GuzzleHttpClient $guzzleClient) { |
||
129 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
130 | $guzzleClient->expects($this->once()) |
||
131 | ->method('createRequest') |
||
132 | ->with( |
||
133 | 'GET', |
||
134 | 'http://api.snd.no/news/v2/' |
||
135 | ) |
||
136 | ->willReturn(new Request('GET', '/')); |
||
137 | }); |
||
138 | |||
139 | $client->getServiceDocument(); |
||
140 | } |
||
141 | |||
142 | public function testGetServiceDocument() |
||
143 | { |
||
144 | $client = $this->getClientWithResponse(200, [], [], function (GuzzleHttpClient $guzzleClient) { |
||
145 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
146 | $guzzleClient->expects($this->once()) |
||
147 | ->method('createRequest') |
||
148 | ->with( |
||
149 | 'GET', |
||
150 | 'http://api.snd.no/news/v2/' |
||
151 | ) |
||
152 | ->willReturn(new Request('GET', '/')); |
||
153 | }); |
||
154 | |||
155 | $result = $client->getServiceDocument(); |
||
156 | $this->assertEquals([], $result); |
||
157 | } |
||
158 | |||
159 | public function testGetSectionsList() |
||
160 | { |
||
161 | $client = $this->getClientWithResponse( |
||
162 | 200, |
||
163 | [], |
||
164 | [], |
||
165 | function (GuzzleHttpClient $guzzleClient) { |
||
166 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
167 | $guzzleClient->expects($this->once()) |
||
168 | ->method('createRequest') |
||
169 | ->with( |
||
170 | 'GET', |
||
171 | 'http://api.snd.no/news/v2/publication/sa/sections' |
||
172 | ) |
||
173 | ->willReturn(new Request('GET', '/sections')); |
||
174 | } |
||
175 | ); |
||
176 | |||
177 | $result = $client->getSectionsList(); |
||
178 | $this->assertEquals([], $result); |
||
179 | } |
||
180 | |||
181 | public function testGetSubsectionsList() |
||
182 | { |
||
183 | $client = $this->getClientWithResponse( |
||
184 | 200, |
||
185 | [], |
||
186 | [], |
||
187 | function (GuzzleHttpClient $guzzleClient) { |
||
188 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
189 | $guzzleClient->expects($this->once()) |
||
190 | ->method('createRequest') |
||
191 | ->with( |
||
192 | 'GET', |
||
193 | 'http://api.snd.no/news/v2/publication/sa/sections/100/subsections' |
||
194 | ) |
||
195 | ->willReturn(new Request('GET', '/sections/100/subsections')); |
||
196 | } |
||
197 | ); |
||
198 | |||
199 | $result = $client->getSubsectionsList(100); |
||
200 | $this->assertEquals([], $result); |
||
201 | } |
||
202 | |||
203 | public function testGetSectionByUniqueName() |
||
204 | { |
||
205 | $client = $this->getClientWithResponse( |
||
206 | 200, |
||
207 | [], |
||
208 | [], |
||
209 | function (GuzzleHttpClient $guzzleClient) { |
||
210 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
211 | $guzzleClient->expects($this->once()) |
||
212 | ->method('createRequest') |
||
213 | ->with( |
||
214 | 'GET', |
||
215 | 'http://api.snd.no/news/v2/publication/sa/sections/instance?uniqueName=sectionName' |
||
216 | ) |
||
217 | ->willReturn(new Request('GET', '/sections/instance?uniqueName=sectionName')); |
||
218 | } |
||
219 | ); |
||
220 | |||
221 | $result = $client->getSectionByUniqueName('sectionName'); |
||
222 | $this->assertEquals([], $result); |
||
223 | } |
||
224 | |||
225 | public function testGetSectionById() |
||
226 | { |
||
227 | $client = $this->getClientWithResponse( |
||
228 | 200, |
||
229 | [], |
||
230 | [], |
||
231 | function (GuzzleHttpClient $guzzleClient) { |
||
232 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
233 | $guzzleClient->expects($this->once()) |
||
234 | ->method('createRequest') |
||
235 | ->with( |
||
236 | 'GET', |
||
237 | 'http://api.snd.no/news/v2/publication/sa/sections/100' |
||
238 | ) |
||
239 | ->willReturn(new Request('GET', '/sections/100')); |
||
240 | } |
||
241 | ); |
||
242 | |||
243 | $result = $client->getSectionById(100); |
||
244 | $this->assertEquals([], $result); |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * @expectedException \Stp\SndApi\News\Exception\InvalidMethodException |
||
249 | */ |
||
250 | public function testGetArticlesBySectionIdWithInvalidMethod() |
||
251 | { |
||
252 | $client = $this->getClient(); |
||
253 | $client->getArticlesBySectionId(100, 'invalid'); |
||
254 | } |
||
255 | |||
256 | /** |
||
257 | * @expectedException \Stp\SndApi\News\Exception\InvalidMethodParametersException |
||
258 | */ |
||
259 | public function testGetArticlesBySectionIdWithInvalidParameters() |
||
264 | |||
265 | View Code Duplication | public function testGetArticlesBySectionIdWithParams() |
|
266 | { |
||
267 | $client = $this->getClientWithResponse( |
||
268 | 200, |
||
269 | [], |
||
270 | [], |
||
271 | function (GuzzleHttpClient $guzzleClient) { |
||
272 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
273 | $guzzleClient->expects($this->once()) |
||
274 | ->method('createRequest') |
||
275 | ->with( |
||
276 | 'GET', |
||
277 | 'http://api.snd.no/news/v2/publication/sa/sections/100/desked?offset=50' |
||
278 | ) |
||
279 | ->willReturn(new Request('GET', '/sections/100/desked?offset=50')); |
||
280 | } |
||
281 | ); |
||
282 | |||
283 | $result = $client->getArticlesBySectionId(100, 'desked', ['offset' => 50]); |
||
284 | $this->assertEquals([], $result); |
||
285 | } |
||
286 | |||
287 | public function testGetArticle() |
||
301 | |||
302 | /** |
||
303 | * @expectedException \Stp\SndApi\News\Exception\InvalidContentTypeException |
||
304 | */ |
||
305 | public function testGetSearchByInstanceWithInvalidContentType() |
||
310 | |||
311 | View Code Duplication | public function testGetSearchByInstance() |
|
312 | { |
||
313 | $client = $this->getClientWithResponse( |
||
314 | 200, |
||
315 | [], |
||
316 | [], |
||
317 | function (GuzzleHttpClient $guzzleClient) { |
||
318 | $url = 'http://api.snd.no/news/v2/publication/sa/searchContents/instance?contentId=100100' . |
||
319 | '&contentType=article'; |
||
320 | |||
321 | /** @var GuzzleHttpClient|\PHPUnit_Framework_MockObject_MockObject $guzzleClient */ |
||
322 | $guzzleClient->expects($this->once()) |
||
323 | ->method('createRequest') |
||
335 | |||
336 | View Code Duplication | public function testGetSearchByCollection() |
|
357 | } |
||
358 |
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.