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
Tests doubles: the motion picture
Search
Fran Iglesias
November 02, 2018
Programming
540
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Tests doubles: the motion picture
Test doubles explained
Fran Iglesias
November 02, 2018
More Decks by Fran Iglesias
See All by Fran Iglesias
Tips for daily refactoring
franiglesias
0
360
Introduction to TDD: Red-Green-Refactor
franiglesias
1
320
Testing value objects
franiglesias
0
280
testing the unpredictable
franiglesias
0
250
Low cost techniques for test doubles
franiglesias
0
240
Other Decks in Programming
See All in Programming
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
190
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
21
6.7k
Make SRE Operations Easier with Azure SRE Agent
kkamegawa
0
6.4k
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
270
代数的データ型って何が嬉しいの? #frontend_phpcon_do
kajitack
8
3.7k
AI 輔助遺留系統現代化的經驗分享
jame2408
1
200
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
360
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
170
ユニットテストの先へ:テスト技法で要求・仕様を整理するJava開発実践 / Beyond_Unit_Testing_Practical_Java_Development_Techniques_for_Organizing_Requirements_and_Specifications
shimashima35
0
410
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
150
スマートグラスで並列バイブコーディング
hyshu
0
150
Inside Stream API
skrb
1
730
Featured
See All Featured
The Language of Interfaces
destraynor
162
27k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.3k
BBQ
matthewcrist
89
10k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
950
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
150
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
610
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Designing for Timeless Needs
cassininazir
1
260
Transcript
TDD 101 6. Test doubles: the motion picture
Test doubles: the motion picture
The plot
You want to test an object that uses collaborators…
You need to isolate its behaviour from that of its
collaborators
Then, you’ll need… test doubles
The argument
A unit of software Can be a query: returns a
response Can be a command: produces a change in the state of the system You should test the results of the behavior
When you test it You want to prove that the
behavior: • Is produced by the code of the unit of software • Is not influenced by any other factor
So, you need to control the behavior of collaborators Cancelling:
no behavior at all Controlling: knowing exactly what they are doing (by means of programming it)
The cast
Dummy No behavior Only interface
namespace Dojo\HappyBirthday\Logger; interface SimpleLogger { public function log(string $channel, string
$message): void; }
namespace Tests\Dojo\HappyBirthday\Double; use Dojo\HappyBirthday\Logger\SimpleLogger; class LoggerDummy implements SimpleLogger { public
function log(string $channel, string $message): void { } }
namespace Tests\Dojo\HappyBirthday; use Dojo\HappyBirthday\SendGreetings; use PHPUnit\Framework\TestCase; class SendGreetingsTest extends TestCase
{ public function testSendGreetingToCustomersWhenIsTheirBirthday() { $clockService = $this->getClockServiceStub(); $logger = $this->getLoggerDummy(); $customerRepository = $this->getCustomerRepositoryStub(); $mailer = $this->getMailerSpy([ new Customer('
[email protected]
'), new Customer('
[email protected]
'), new Customer('
[email protected]
') ]); $sendGreetings = new SendGreetings( $clockService, $customerRepository, $mailer, $logger ); $sendGreetings->execute(); $this->assertEquals(3. $mailer->getMessagesSent()); } }
Stub Programmed behavior
namespace Dojo\HappyBirthday\Clock; use DateTimeImmutable; interface ClockService { public function currentDate():
DateTimeImmutable; }
namespace Tests\Dojo\HappyBirthday\Double; use DateTimeImmutable; use Dojo\HappyBirthday\Clock\ClockService; class ClockServiceStub implements ClockService
{ /** @var DateTimeImmutable */ private $dateTime; public function __construct(DateTimeImmutable $dateTime) { $this->dateTime = $dateTime; } public function currentDate() : DateTimeImmutable { return $this->dateTime; } }
namespace Tests\Dojo\HappyBirthday; use Dojo\HappyBirthday\SendGreetings; use PHPUnit\Framework\TestCase; class SendGreetingsTest extends TestCase
{ public function testSendGreetingToCustomersWhenIsTheirBirthday() { $clockService = $this->getClockServiceStub(); $logger = $this->getLoggerDummy(); $customerRepository = $this->getCustomerRepositoryStub(); $mailer = $this->getMailerSpy([ new Customer('
[email protected]
'), new Customer('
[email protected]
'), new Customer('
[email protected]
') ]); $sendGreetings = new SendGreetings( $clockService, $customerRepository, $mailer, $logger ); $sendGreetings->execute(); $this->assertEquals(3. $mailer->getMessagesSent()); } }
Fake Behavior implementation… but best suited for testing Needs its
own tests
namespace Dojo\HappyBirthday\Contacts; interface ContactRepositoryInterface { public function retrieveById(UUid $uuid): Contact;
}
namespace Dojo\HappyBirthday\Contacts; class InMemoryContactRepository implements ContactRepository { public function retrieveById(UUid
$uuid): Contact { } }
Spy Registers how is used Fragility (coupling)
interface Mailer { public function send(Message $message) : void; }
class MailerSpy implements Mailer { private $calls = 0; public
function send(Message $message) : void { $this->calls++; } public function getCalls() { return $this->calls; } }
Mock Has expectations about how is used Takes assertions away
from the test Fragility (coupling)
Taxonomy
Behavior Knowledge
test doubles by behavior dummy stub fake no behavior fixed
complete Applies to any kind of double by knowledge
test doubles by knowledge passive spy mock Applies to any
kind of double by behavior knows nothing registers use has expectations
How to
i
Design principles Dem SRP OCP DIP ISP LSP DRY Yagni
The “real” object Should have: • No behavior • No
side effects • Immutability
Self-shunt Exploratory and sparse use Simple interface
class ServiceTest extends TestCase implements Mailer { private $mailerCalls =
0; public function testMailer() { $sut = new Service($this); $sut->execute(); $this->assertEquals(2, $this->getCalls()); } public function send(Message $message) : void { $this->mailerCalls++; } }
Anonymous class Exploratory Single use Simple interface No side effects
class ServiceTest extends TestCase { public function testMailer() { $mailer
= new class implements Mailer { private $calls = 0; public function send(Message $message) : void { $this->calls++; } puablic function getCalls() { return $this->calls; } }; $sut = new Service($mailer); $sut->execute(); $this->assertEquals(2, $mailer->getCalls()); } }
Hand made double Simple interfaces Simple behaviour Could need its
own tests
Mocking library Large interfaces Complex behaviour Multiple scenarios
class ServiceTest extends TestCase { public function testMailer() { $mailer
= $this->createMock(Mailer::class); $mailer->expects($this->once()) ->method(‘send’) ->with($this->isInstanceOf(Message::class)) ->willReturn(true); $sut = new Service($mailer); $sut->execute(); } }
None