Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Testing Legacy Troubles
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
konrad_126
April 13, 2022
Programming
53
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Testing Legacy Troubles
konrad_126
April 13, 2022
More Decks by konrad_126
See All by konrad_126
Build the right thing
konrad_126
0
120
Build the right thing
konrad_126
0
110
Just D(DD)o it!
konrad_126
0
180
Sailing briefing
konrad_126
0
200
Git under the hood
konrad_126
0
200
No Jira, No Cry
konrad_126
0
190
remotewithlove
konrad_126
0
80
Domain storytelling
konrad_126
0
130
Get, set... STOP
konrad_126
0
200
Other Decks in Programming
See All in Programming
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
130
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
14
5.6k
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.7k
net-httpのHTTP/2対応について
naruse
0
500
Webフレームワークの ベンチマークについて
yusukebe
0
170
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
160
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
790
AIだと陥りがちなJakarta EE最新技術への移行時の落とし穴と解決策
tnagao7
0
110
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
540
New "Type" system on PicoRuby
pocke
1
970
そのテスト、説明できますか?~LWテスト戦略FW~のご紹介
nakahara
0
150
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
110
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Into the Great Unknown - MozCon
thekraken
41
2.6k
Technical Leadership for Architectural Decision Making
baasie
3
420
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
210
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
410
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
420
First, design no harm
axbom
PRO
2
1.2k
The Limits of Empathy - UXLibs8
cassininazir
1
360
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
170
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Transcript
TESTING LEGACY TROUBLES @konrad_126
LEGACY CODE? NO TESTS.
THE CASE OF AN IRRITATING PARAMETER
<?php class CalculatePrice { public function __construct(private VatDotComClient $vatProvider) {
} public function calculate(Product $product) : float { $taxRate = $this->vatProvider->getRate($product->countryCode()); // some business logic to calculate price } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public function __construct(private VatDotComClient $vatProvider) <?php 1 2 class CalculatePrice 3 { 4 5 { 6 } 7 8 public function calculate(Product $product) : float 9 { 10 $taxRate = $this->vatProvider->getRate($product->countryCode()); 11 // some business logic to calculate price 12 } 13 } 14 $taxRate = $this->vatProvider->getRate($product->countryCode()); <?php 1 2 class CalculatePrice 3 { 4 public function __construct(private VatDotComClient $vatProvider) 5 { 6 } 7 8 public function calculate(Product $product) : float 9 { 10 11 // some business logic to calculate price 12 } 13 } 14 // some business logic to calculate price <?php 1 2 class CalculatePrice 3 { 4 public function __construct(private VatDotComClient $vatProvider) 5 { 6 } 7 8 public function calculate(Product $product) : float 9 { 10 $taxRate = $this->vatProvider->getRate($product->countryCode()); 11 12 } 13 } 14
<?php class CalculatePriceTest { public function itAppliesTheTaxRate() { $calculateTax =
new CalculatePrice( new VatDotComClient('api-key', 'secret') ); // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 $calculateTax = new CalculatePrice( <?php 1 2 class CalculatePriceTest 3 { 4 public function itAppliesTheTaxRate() 5 { 6 7 new VatDotComClient('api-key', 'secret') 8 ); 9 // ... 10 } 11 } 12 new VatDotComClient('api-key', 'secret') <?php 1 2 class CalculatePriceTest 3 { 4 public function itAppliesTheTaxRate() 5 { 6 $calculateTax = new CalculatePrice( 7 8 ); 9 // ... 10 } 11 } 12
<?php class CalculatePriceTest { public function itAppliesTheTaxRate() { // ...
} public function itAppliesDiscount() { // ... } public function itAppliesVoucher() { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 vat.com
<?php class CalculatePriceTest { public function itAppliesTheTaxRate() { // ...
} public function itAppliesDiscount() { // ... } public function itAppliesVoucher() { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 dummy VAT provider
<?php class CalculatePrice { public function __construct(private VatDotComClient $vatProvider) {
} public function calculate(Product $product) { $taxRate = $this->vatProvider->getRate($product->countryCode()); // some business logic to calculate price } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public function __construct(private VatDotComClient $vatProvider) <?php 1 2 class CalculatePrice 3 { 4 5 { 6 } 7 8 public function calculate(Product $product) 9 { 10 $taxRate = $this->vatProvider->getRate($product->countryCode()); 11 // some business logic to calculate price 12 } 13 } 14
<?php interface VatProvider { public function getRate(string $countryCode): float; }
1 2 3 4 5 6 Extract Interface
<?php class CalculatePrice { public function __construct(private VatProvider $vatProvider) {
} public function calculate(Product $product) { $taxRate = $this->vatProvider->getRate($product->countryCode()); // some business logic to calculate price } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public function __construct(private VatProvider $vatProvider) <?php 1 2 class CalculatePrice 3 { 4 5 { 6 } 7 8 public function calculate(Product $product) 9 { 10 $taxRate = $this->vatProvider->getRate($product->countryCode()); 11 // some business logic to calculate price 12 } 13 } 14
<?php class TestProvider implements VatProvider { public function __construct(private float
$rate) { } public function getRate(string $countryCode) { return $this->rate; } } 1 2 3 4 5 6 7 8 9 10 11 12 13 class TestProvider implements VatProvider <?php 1 2 3 { 4 public function __construct(private float $rate) 5 { 6 } 7 8 public function getRate(string $countryCode) 9 { 10 return $this->rate; 11 } 12 } 13 public function __construct(private float $rate) <?php 1 2 class TestProvider implements VatProvider 3 { 4 5 { 6 } 7 8 public function getRate(string $countryCode) 9 { 10 return $this->rate; 11 } 12 } 13 return $this->rate; <?php 1 2 class TestProvider implements VatProvider 3 { 4 public function __construct(private float $rate) 5 { 6 } 7 8 public function getRate(string $countryCode) 9 { 10 11 } 12 } 13
<?php public function itAppliesTheTaxRate() { $calculateTax = new CalculatePrice( new
TestProvider(0.25) ); // ... Assert price what expected (with 0.25 tax rate) } 1 2 3 4 5 6 7 8 9 10 $calculateTax = new CalculatePrice( <?php 1 2 public function itAppliesTheTaxRate() 3 { 4 5 new TestProvider(0.25) 6 ); 7 8 // ... Assert price what expected (with 0.25 tax rate) 9 } 10 new TestProvider(0.25) <?php 1 2 public function itAppliesTheTaxRate() 3 { 4 $calculateTax = new CalculatePrice( 5 6 ); 7 8 // ... Assert price what expected (with 0.25 tax rate) 9 } 10
THE CASE HIDDEN DEPENDENCY
<?php class ProcessPayment { public function __construct() { // ...
} public function process(Payment $payment) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public function __construct() <?php 1 2 class ProcessPayment 3 { 4 5 { 6 // ... 7 } 8 9 public function process(Payment $payment) 10 { 11 // ... 12 } 13 } 14
<?php public function itRecordsThePayment() { $payment = new Payment(340, 'EUR',
12); $processPayment = new ProcessPayment(); $processpayments->process($payment); // ... Assert stuff } 1 2 3 4 5 6 7 8 9 10 11
<?php class ProcessPayment { public function __construct() { // some
code $this->mailer = new Mailer('api-key', 'secret'); // some code } public function process(Payment $payment) { // ... $this->mailer->send( $payment->receiver(), new PaymentNotificationMessage($payment) ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 $this->mailer = new Mailer('api-key', 'secret'); <?php 1 2 class ProcessPayment 3 { 4 public function __construct() 5 { 6 // some code 7 8 // some code 9 } 10 11 public function process(Payment $payment) 12 { 13 // ... 14 15 $this->mailer->send( 16 $payment->receiver(), 17 new PaymentNotificationMessage($payment) 18 ); 19 20 } 21 } 22 $this->mailer->send( $payment->receiver(), new PaymentNotificationMessage($payment) ); } } <?php 1 2 class ProcessPayment 3 { 4 public function __construct() 5 { 6 // some code 7 $this->mailer = new Mailer('api-key', 'secret'); 8 // some code 9 } 10 11 public function process(Payment $payment) 12 { 13 // ... 14 15 16 17 18 19 20 21 22
<?php class ProcessPayment { public function __construct() { $this->mailer =
new Mailer('api-key', 'secret'); } public function process(Payment $payment) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php class ProcessPayment { public function __construct(Mailer $mailer) { $this->mailer
= $mailer; } public function process(Payment $payment) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Parameterize Constructor (Extract Interface)
DESIGN?
dependency injection principle strategy design pattern depend on abstract not
a concrete
MORE ADVICE?
THANK YOU @konrad_126