Complex classes like OrderSpec 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 OrderSpec, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | final class OrderSpec extends ObjectBehavior |
||
35 | { |
||
36 | function it_is_initializable() |
||
40 | |||
41 | function it_implements_an_order_interface() |
||
42 | { |
||
43 | $this->shouldImplement(OrderInterface::class); |
||
44 | } |
||
45 | |||
46 | function it_extends_an_order() |
||
47 | { |
||
48 | $this->shouldHaveType(BaseOrder::class); |
||
49 | } |
||
50 | |||
51 | function it_does_not_have_a_customer_defined_by_default() |
||
52 | { |
||
53 | $this->getCustomer()->shouldReturn(null); |
||
54 | } |
||
55 | |||
56 | function itx_allows_defining_customer(CustomerInterface $customer) |
||
57 | { |
||
58 | $this->setCustomer($customer); |
||
59 | $this->getCustomer()->shouldReturn($customer); |
||
60 | } |
||
61 | |||
62 | function its_channel_is_mutable(ChannelInterface $channel) |
||
67 | |||
68 | function it_does_not_have_shipping_address_by_default() |
||
69 | { |
||
70 | $this->getShippingAddress()->shouldReturn(null); |
||
71 | } |
||
72 | |||
73 | function it_allows_defining_shipping_address(AddressInterface $address) |
||
74 | { |
||
75 | $this->setShippingAddress($address); |
||
76 | $this->getShippingAddress()->shouldReturn($address); |
||
77 | } |
||
78 | |||
79 | function it_does_not_have_billing_address_by_default() |
||
80 | { |
||
81 | $this->getBillingAddress()->shouldReturn(null); |
||
82 | } |
||
83 | |||
84 | function it_allows_defining_billing_address(AddressInterface $address) |
||
85 | { |
||
86 | $this->setBillingAddress($address); |
||
87 | $this->getBillingAddress()->shouldReturn($address); |
||
88 | } |
||
89 | |||
90 | function its_checkout_state_is_mutable() |
||
95 | |||
96 | function its_payment_state_is_mutable() |
||
101 | |||
102 | function it_initializes_item_units_collection_by_default() |
||
103 | { |
||
104 | $this->getItemUnits()->shouldHaveType(Collection::class); |
||
105 | } |
||
106 | |||
107 | function it_initializes_shipments_collection_by_default() |
||
108 | { |
||
109 | $this->getShipments()->shouldHaveType(Collection::class); |
||
110 | } |
||
111 | |||
112 | function it_adds_shipment_properly(ShipmentInterface $shipment) |
||
113 | { |
||
114 | $this->shouldNotHaveShipment($shipment); |
||
115 | |||
116 | $shipment->setOrder($this)->shouldBeCalled(); |
||
117 | $this->addShipment($shipment); |
||
118 | |||
119 | $this->shouldHaveShipment($shipment); |
||
120 | } |
||
121 | |||
122 | function it_removes_a_shipment_properly(ShipmentInterface $shipment) |
||
123 | { |
||
124 | $shipment->setOrder($this)->shouldBeCalled(); |
||
125 | $this->addShipment($shipment); |
||
126 | |||
127 | $this->shouldHaveShipment($shipment); |
||
128 | |||
129 | $shipment->setOrder(null)->shouldBeCalled(); |
||
130 | $this->removeShipment($shipment); |
||
131 | |||
132 | $this->shouldNotHaveShipment($shipment); |
||
133 | } |
||
134 | |||
135 | function it_removes_shipments(ShipmentInterface $shipment) |
||
136 | { |
||
137 | $this->addShipment($shipment); |
||
138 | $this->hasShipment($shipment)->shouldReturn(true); |
||
139 | |||
140 | $this->removeShipments(); |
||
141 | |||
142 | $this->hasShipment($shipment)->shouldReturn(false); |
||
143 | } |
||
144 | |||
145 | function it_returns_shipping_adjustments( |
||
146 | AdjustmentInterface $shippingAdjustment, |
||
147 | AdjustmentInterface $taxAdjustment |
||
148 | ) { |
||
149 | $shippingAdjustment->getType()->willReturn(AdjustmentInterface::SHIPPING_ADJUSTMENT); |
||
150 | $shippingAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
151 | $shippingAdjustment->isNeutral()->willReturn(true); |
||
152 | |||
153 | $taxAdjustment->getType()->willReturn(AdjustmentInterface::TAX_ADJUSTMENT); |
||
154 | $taxAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
155 | $taxAdjustment->isNeutral()->willReturn(true); |
||
156 | |||
157 | $this->addAdjustment($shippingAdjustment); |
||
158 | $this->addAdjustment($taxAdjustment); |
||
159 | |||
160 | $this->getAdjustments()->count()->shouldReturn(2); |
||
161 | |||
162 | $shippingAdjustments = $this->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT); |
||
163 | $shippingAdjustments->count()->shouldReturn(1); |
||
164 | $shippingAdjustments->first()->shouldReturn($shippingAdjustment); |
||
165 | } |
||
166 | |||
167 | function it_removes_shipping_adjustments( |
||
168 | AdjustmentInterface $shippingAdjustment, |
||
169 | AdjustmentInterface $taxAdjustment |
||
170 | ) { |
||
171 | $shippingAdjustment->getType()->willReturn(AdjustmentInterface::SHIPPING_ADJUSTMENT); |
||
172 | $shippingAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
173 | $shippingAdjustment->isNeutral()->willReturn(true); |
||
174 | |||
175 | $taxAdjustment->getType()->willReturn(AdjustmentInterface::TAX_ADJUSTMENT); |
||
176 | $taxAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
177 | $taxAdjustment->isNeutral()->willReturn(true); |
||
178 | |||
179 | $this->addAdjustment($shippingAdjustment); |
||
180 | $this->addAdjustment($taxAdjustment); |
||
181 | |||
182 | $this->getAdjustments()->count()->shouldReturn(2); |
||
183 | |||
184 | $shippingAdjustment->isLocked()->willReturn(false); |
||
185 | $shippingAdjustment->setAdjustable(null)->shouldBeCalled(); |
||
186 | $this->removeAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT); |
||
187 | |||
188 | $this->getAdjustments()->count()->shouldReturn(1); |
||
189 | $this->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT)->count()->shouldReturn(0); |
||
190 | } |
||
191 | |||
192 | function it_returns_tax_adjustments( |
||
193 | AdjustmentInterface $shippingAdjustment, |
||
194 | AdjustmentInterface $taxAdjustment |
||
195 | ) { |
||
196 | $shippingAdjustment->getType()->willReturn(AdjustmentInterface::SHIPPING_ADJUSTMENT); |
||
197 | $shippingAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
198 | $shippingAdjustment->isNeutral()->willReturn(true); |
||
199 | |||
200 | $taxAdjustment->getType()->willReturn(AdjustmentInterface::TAX_ADJUSTMENT); |
||
201 | $taxAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
202 | $taxAdjustment->isNeutral()->willReturn(true); |
||
203 | |||
204 | $this->addAdjustment($shippingAdjustment); |
||
205 | $this->addAdjustment($taxAdjustment); |
||
206 | |||
207 | $this->getAdjustments()->count()->shouldReturn(2); |
||
208 | |||
209 | $taxAdjustments = $this->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT); |
||
210 | $taxAdjustments->count()->shouldReturn(1); |
||
211 | $taxAdjustments->first()->shouldReturn($taxAdjustment); |
||
212 | } |
||
213 | |||
214 | function it_removes_tax_adjustments( |
||
215 | AdjustmentInterface $shippingAdjustment, |
||
216 | AdjustmentInterface $taxAdjustment |
||
217 | ) { |
||
218 | $shippingAdjustment->getType()->willReturn(AdjustmentInterface::SHIPPING_ADJUSTMENT); |
||
219 | $shippingAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
220 | $shippingAdjustment->isNeutral()->willReturn(true); |
||
221 | |||
222 | $taxAdjustment->getType()->willReturn(AdjustmentInterface::TAX_ADJUSTMENT); |
||
223 | $taxAdjustment->setAdjustable($this)->shouldBeCalled(); |
||
224 | $taxAdjustment->isNeutral()->willReturn(true); |
||
225 | |||
226 | $this->addAdjustment($shippingAdjustment); |
||
227 | $this->addAdjustment($taxAdjustment); |
||
228 | |||
229 | $this->getAdjustments()->count()->shouldReturn(2); |
||
230 | |||
231 | $taxAdjustment->isLocked()->willReturn(false); |
||
232 | $taxAdjustment->setAdjustable(null)->shouldBeCalled(); |
||
233 | $this->removeAdjustments(AdjustmentInterface::TAX_ADJUSTMENT); |
||
234 | |||
235 | $this->getAdjustments()->count()->shouldReturn(1); |
||
236 | $this->getAdjustments(AdjustmentInterface::TAX_ADJUSTMENT)->count()->shouldReturn(0); |
||
237 | } |
||
238 | |||
239 | function it_does_not_have_a_currency_code_defined_by_default() |
||
240 | { |
||
241 | $this->getCurrencyCode()->shouldReturn(null); |
||
242 | } |
||
243 | |||
244 | function it_allows_defining_a_currency_code() |
||
245 | { |
||
246 | $this->setCurrencyCode('PLN'); |
||
247 | $this->getCurrencyCode()->shouldReturn('PLN'); |
||
248 | } |
||
249 | |||
250 | function it_has_no_default_locale_code() |
||
251 | { |
||
252 | $this->getLocaleCode()->shouldReturn(null); |
||
253 | } |
||
254 | |||
255 | function its_locale_code_is_mutable() |
||
256 | { |
||
257 | $this->setLocaleCode('en'); |
||
258 | $this->getLocaleCode()->shouldReturn('en'); |
||
259 | } |
||
260 | |||
261 | function it_has_a_cart_shipping_state_by_default() |
||
262 | { |
||
263 | $this->getShippingState()->shouldReturn(OrderShippingStates::STATE_CART); |
||
264 | } |
||
265 | |||
266 | function its_shipping_state_is_mutable() |
||
267 | { |
||
268 | $this->setShippingState(OrderShippingStates::STATE_SHIPPED); |
||
269 | $this->getShippingState()->shouldReturn(OrderShippingStates::STATE_SHIPPED); |
||
270 | } |
||
271 | |||
272 | function it_adds_and_removes_payments(PaymentInterface $payment) |
||
273 | { |
||
274 | $payment->getState()->willReturn(PaymentInterface::STATE_NEW); |
||
275 | $payment->setOrder($this)->shouldBeCalled(); |
||
276 | |||
277 | $this->addPayment($payment); |
||
278 | $this->shouldHavePayment($payment); |
||
279 | |||
280 | $payment->setOrder(null)->shouldBeCalled(); |
||
281 | |||
282 | $this->removePayment($payment); |
||
283 | $this->shouldNotHavePayment($payment); |
||
284 | } |
||
285 | |||
286 | function it_returns_last_payment_with_given_state( |
||
287 | PaymentInterface $payment1, |
||
288 | PaymentInterface $payment2, |
||
289 | PaymentInterface $payment3, |
||
290 | PaymentInterface $payment4 |
||
291 | ) { |
||
292 | $payment1->getState()->willReturn(PaymentInterface::STATE_CART); |
||
293 | $payment1->setOrder($this)->shouldBeCalled(); |
||
294 | |||
295 | $payment2->getState()->willReturn(PaymentInterface::STATE_CANCELLED); |
||
296 | $payment2->setOrder($this)->shouldBeCalled(); |
||
297 | |||
298 | $payment3->getState()->willReturn(PaymentInterface::STATE_PROCESSING); |
||
299 | $payment3->setOrder($this)->shouldBeCalled(); |
||
300 | |||
301 | $payment4->getState()->willReturn(PaymentInterface::STATE_FAILED); |
||
302 | $payment4->setOrder($this)->shouldBeCalled(); |
||
303 | |||
304 | $this->addPayment($payment1); |
||
305 | $this->addPayment($payment2); |
||
306 | $this->addPayment($payment3); |
||
307 | $this->addPayment($payment4); |
||
308 | |||
309 | $this->getLastPayment(OrderInterface::STATE_CART)->shouldReturn($payment1); |
||
310 | } |
||
311 | |||
312 | function it_returns_a_null_if_there_is_no_payments_after_trying_to_get_last_payment() |
||
313 | { |
||
314 | $this->getLastPayment(OrderInterface::STATE_CART)->shouldReturn(null); |
||
315 | } |
||
316 | |||
317 | function it_returns_last_payment_with_any_state_if_there_is_no_target_state_specified( |
||
318 | PaymentInterface $payment1, |
||
319 | PaymentInterface $payment2, |
||
320 | PaymentInterface $payment3, |
||
321 | PaymentInterface $payment4 |
||
322 | ) { |
||
323 | $payment1->getState()->willReturn(PaymentInterface::STATE_CART); |
||
324 | $payment1->setOrder($this)->shouldBeCalled(); |
||
325 | |||
326 | $payment2->getState()->willReturn(PaymentInterface::STATE_CANCELLED); |
||
327 | $payment2->setOrder($this)->shouldBeCalled(); |
||
328 | |||
329 | $payment3->getState()->willReturn(PaymentInterface::STATE_PROCESSING); |
||
330 | $payment3->setOrder($this)->shouldBeCalled(); |
||
331 | |||
332 | $payment4->getState()->willReturn(PaymentInterface::STATE_FAILED); |
||
333 | $payment4->setOrder($this)->shouldBeCalled(); |
||
334 | |||
335 | $this->addPayment($payment1); |
||
336 | $this->addPayment($payment2); |
||
337 | $this->addPayment($payment3); |
||
338 | $this->addPayment($payment4); |
||
339 | |||
340 | $this->getLastPayment()->shouldReturn($payment4); |
||
341 | } |
||
342 | |||
343 | function it_adds_and_removes_shipments(ShipmentInterface $shipment) |
||
355 | |||
356 | function it_has_a_promotion_coupon(PromotionCouponInterface $coupon) |
||
361 | |||
362 | function it_counts_promotions_subjects(OrderItemInterface $item1, OrderItemInterface $item2) |
||
371 | |||
372 | function it_adds_and_removes_promotions(PromotionInterface $promotion) |
||
380 | |||
381 | function it_returns_0_tax_total_when_there_are_no_items_and_adjustments() |
||
385 | |||
386 | function it_returns_a_tax_of_all_items_as_tax_total_when_there_are_no_tax_adjustments( |
||
402 | |||
403 | function it_returns_a_tax_of_all_items_and_non_neutral_shipping_tax_as_tax_total( |
||
434 | |||
435 | function it_returns_a_tax_of_all_items_and_neutral_shipping_tax_as_tax_total( |
||
466 | |||
467 | function it_includes_a_non_neutral_tax_adjustments_in_shipping_total( |
||
486 | |||
487 | function it_returns_a_shipping_total_decreased_by_shipping_promotion( |
||
513 | |||
514 | function it_does_not_include_neutral_tax_adjustments_in_shipping_total( |
||
533 | |||
534 | function it_returns_0_as_promotion_total_when_there_are_no_order_promotion_adjustments() |
||
538 | |||
539 | function it_returns_a_sum_of_all_order_promotion_adjustments_applied_to_items_as_order_promotion_total( |
||
556 | |||
557 | function it_does_not_include_a_shipping_promotion_adjustment_in_order_promotion_total( |
||
576 | |||
577 | function it_has_a_token_value() |
||
583 | |||
584 | function it_has_customer_ip() |
||
585 | { |
||
586 | $this->setCustomerIp('172.16.254.1'); |
||
587 | $this->getCustomerIp()->shouldReturn('172.16.254.1'); |
||
588 | } |
||
589 | } |
||
590 |
Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.