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
例外の正しい扱い方 そのエラー try-catchして大丈夫?
jinwatanabe
0
350
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
130
共通化で考えるべきは、実装より公開する型だった
codeegg
0
180
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.8k
OSINT for SRE: 学術論文とポストモーテムから探る システム障害の共通パターン / SRE NEXT 2026
tomoyk
1
3.2k
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
3.6k
フィードバックで育てるAI開発
kotaminato
1
110
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
5.4k
Developing with AI Agents — Codex, Claude Code & Cowork Practical Guide
x5gtrn
PRO
0
1.3k
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
410
AIエージェントで 変わるAndroid開発環境
takahirom
2
480
Featured
See All Featured
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
220
Making the Leap to Tech Lead
cromwellryan
135
10k
Fashionably flexible responsive web design (full day workshop)
malarkey
408
67k
How STYLIGHT went responsive
nonsquared
100
6.2k
ラッコキーワード サービス紹介資料
rakko
1
3.9M
Crafting Experiences
bethany
1
210
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1k
We Have a Design System, Now What?
morganepeng
55
8.2k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.9k
Bash Introduction
62gerente
615
220k
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