SlideShare a Scribd company logo
1 of 79
Imagine a world
without mocks
@KenScambler
Scala Developer at
Me
14 years
5 years
5 years
when possible
when bored
when forced
http://techblog.realestate.com.au/to-kill-a-mockingtest/
Q: What’s so bad about
mocks & stubs?
A: The problem they solve is
“how to test poorly designed
code”
How did we get here?
UserRepo
UserService
User getUser(UserId)
DB
AuthService
boolean authUser(UserId)
Collaborators galore!
Record selectUser(SQL)
UserRepo
UserService
User getUser(UserId)
DB
AuthService
boolean authUser(UserId)
Record selectUser(SQL)
How to separate UserService?
http://martinfowler.com/articles/mocksArentStubs.html
Stubs provide canned answers
to calls made during the test,
usually not responding at all to
anything outside what's
programmed in for the test.
UserService
User getUser(UserId)
If you ask me
“authUser(1234)”,
I’ll say “true”
Stub
UserRepo
DB
Record selectUser(SQL)
UserService
User getUser(UserId)
Stub
UserRepo
Record selectUser(SQL)
UserService’s
input is now
deterministic!
If you ask me
“authUser(1234)”,
I’ll say “true”
DB
http://martinfowler.com/articles/mocksArentStubs.html
Mocks are objects pre-
programmed with
expectations which form a
specification of the calls
they are expected to
receive.
UserService
User getUser(UserId)
I expect
“selectUser()”
to be called once
Mock
If you ask me
“authUser(1234)”,
I’ll say “true”
UserService
User getUser(UserId)
I expect
“selectUser()”
to be called once
Mock
UserService’s
output is now
deterministic!
If you ask me
“authUser(1234)”,
I’ll say “true”
UserService
User getUser(UserId)
Mock
Deterministic
output
Deterministic
input
= Fairly sane test
So far so good.
But wait!
There’s a cost…
1.
Coupled to brittle
implementation
details.
UserService
User getUser(UserId)
Mock
What if an equivalent
method is called
instead? If you ask me
“authUser(1234)”,
I’ll say “true”
authLocalUser(1234)
Stub
UserService
User getUser(UserId)
Ah shit.
authLocalUser(1234)
UserService
User getUser(UserId)
Honestly, no
one’s asked me
that before.
authLocalUser(1234)
UserService
User getUser(UserId)
I’m just a sock.
authLocalUser(1234)
2.
Somewhat misses the
point of the test
UserService
User getUser(UserId)
authLocalUser(1234)
I expect
“selectUser()”
to be called once
Still no idea.
UserService
User getUser(UserId)
IT DIDN’T GET
CALLED!!! NOTHING
HAPPENED!!!!!
UserService
User getUser(UserId)
IT DIDN’T GET
CALLED!!! NOTHING
HAPPENED!!!!!
Real problem:
The stub configuration was
out of date.
Case study #1
Clumsy input
public interface Config {
// Database stuff
String getDatabaseHost();
int getDatabasePort();
int getMaxThreads();
int getConnectionTimeout();
// Potato settings
String getDefaultPotatoVariety();
int getMaxPotatoes();
double getPotatoShininess();
// Sacrificial settings
int getBloodSacrificeGoatCount();
int getBloodSacrificeChickenCount();
int getBloodSacrificeSheepCount();
}
public class PotatoService {
public PotatoService(Config config) {
this.potatoVariety = config.getPotatoVariety();
this.maxPotatoes = config.getMaxPotatoes();
}
public Salad makePotatoSalad() {...}
}
public class PotatoServiceTest {
Config config = mock(Config.class)
@Before
public void before() {
when(config.getDefaultPotatoVariety())
.thenReturn(“pontiac”);
when(config.getMaxPotatoes())
.thenReturn(33);
}
public testMakeSalad() {
PotatoService service = new PotatoService();
Assert.equalTo(service.makeSalad(), ...);
}
}
public class PotatoServiceTest {
Config config = mock(Config.class)
@Before
public void before() {
when(config.getDefaultPotatoVariety())
.thenReturn(“pontiac”);
when(config.getMaxPotatoes())
.thenReturn(33);
}
public testMakeSalad() {
PotatoService service = new PotatoService();
Assert.equalTo(service.makeSalad(), ...);
}
}
Stub
Looks ok. But what is the
stub trying to tell us?
No-ones ever
going to
need all those
things at once.
public interface Config {
// Database stuff
String getDatabaseHost();
int getDatabasePort();
int getMaxThreads();
int getConnectionTimeout();
// Potato settings
String getDefaultPotatoVariety();
int getMaxPotatoes();
double getPotatoShininess();
// Sacrificial settings
int getBloodSacrificeGoatCount();
int getBloodSacrificeChickenCount();
int getBloodSacrificeSheepCount();
}
That’s better!
public interface DatabaseConfig {
String getDatabaseHost();
int getDatabasePort();
int getMaxThreads();
int getConnectionTimeout();
}
public interface PotatoConfig {
String getDefaultPotatoVariety();
int getMaxPotatoes();
double getPotatoShininess();
}
public interface SacrificialConfig {
int getBloodSacrificeGoatCount();
int getBloodSacrificeChickenCount();
int getBloodSacrificeSheepCount();
}
public class PotatoService {
public PotatoService(PotatoConfig config) {
this.potatoVariety = config.getPotatoVariety();
this.maxPotatoes = config.getMaxPotatoes();
}
public Salad makePotatoSalad() {...}
}
Don’t you just need the two
fields? Does it matter where
they come from?
public class PotatoService {
public PotatoService(String variety, int max) {
this.potatoVariety = variety;
this.maxPotatoes = max;
}
public Salad makePotatoSalad() {...}
}
The application wiring can
be someone else’s business.
public class PotatoServiceTest {
public testMakeSalad() {
PotatoService service =
new PotatoService(“pontiac”, 33);
Assert.equalTo(service.makeSalad(), ...);
}
}
- More modular
- More reusable
- Simpler
- Less code
- Stubs are gone
Case study #2
Unnecessary mutable
state
public interface Wallet {
int removeCoins(int amount);
int getAmount();
}
public interface VendingMachine {
void insertCoins(int amount);
Can collectCan();
int getStoredCash();
}
public interface Customer {
void buyDrink();
}
public class CustomerTest {
Wallet wallet = mock(Wallet.class);
VendingMachine machine = mock(VendingMachine.class);
@Before
public void before() {
when(wallet.removeCoins(3)).thenReturn(3);
when(vendingMachine.collectCan())
.thenReturn(new CokeCan());
}
public testBuyDrink() {
Customer c = new Customer();
c.buyDrink();
verify(wallet).removeCoins(3);
verify(vendingMachine).insertCoins(3);
verify(vendingMachine).collectCan();
}
}
public class CustomerTest {
Wallet wallet = mock(Wallet.class);
VendingMachine machine = mock(VendingMachine.class);
@Before
public void before() {
when(wallet.removeCoins(3)).thenReturn(3);
when(vendingMachine.collectCan())
.thenReturn(new CokeCan());
}
public testBuyDrink() {
Customer c = new Customer();
c.buyDrink();
verify(wallet).removeCoins(3);
verify(vendingMachine).insertCoins(3);
verify(vendingMachine).collectCan();
}
}
Stub
Mock
The class under test is
separated now!
But what are the mocks
telling us?
public interface Wallet {
int removeCoins(int amount);
int getAmount();
}
public interface VendingMachine {
void insertCoins(int amount);
Can collectCan();
int getStoredCash();
}
public interface Customer {
void buyDrink();
}
Surely we care about
the resulting state,
not the in-betweeny
verbs.
If the state is just
immutable
values, we don’t
have to force
isolation
public interface Wallet {
int removeCoins(int amount);
int getAmount();
}
public interface VendingMachine {
void insertCoins(int amount);
Can collectCan();
int getStoredCash();
}
public interface Customer {
void buyDrink();
}
public interface Wallet {
int getAmount();
Wallet removeCoins(int amount);
}
public interface VendingMachine {
Optional<Can> getCanInTray();
int getStoredCash();
List<Can> getCansInMachine();
VendingMachine insertCoins(int amount);
VendingMachine collectCan();
}
public interface Customer {
Wallet getWallet();
List<Can> getCansHeld();
Pair<VendingMachine, Customer>
buyDrink(VendingMachine vm);
}
public interface Wallet {
int getAmount();
Wallet removeCoins(int amount);
}
public interface VendingMachine {
Optional<Can> getCanInTray();
int getStoredCash();
List<Can> getCansInMachine();
VendingMachine insertCoins(int amount);
VendingMachine collectCan();
}
public interface Customer {
Wallet getWallet();
List<Can> getCansHeld();
Pair<VendingMachine, Customer>
buyDrink(VendingMachine vm);
}
Immutable
state
public interface Wallet {
int getAmount();
Wallet removeCoins(int amount);
}
public interface VendingMachine {
Optional<Can> getCanInTray();
int getStoredCash();
List<Can> getCansInMachine();
VendingMachine insertCoins(int amount);
VendingMachine collectCan();
}
public interface Customer {
Wallet getWallet();
List<Can> getCansHeld();
Pair<VendingMachine, Customer>
buyDrink(VendingMachine vm);
}
“Actions” just
return new
copies
public class CustomerTest {
public testBuyDrink() {
Customer c = new Customer(new Wallet(23));
VendingMachine vm = new VendingMachine(10,30);
Pair<VendingMachine, Customer> result = c.buyDrink(vm);
Customer c2 = result.second();
VendingMachine vm2 = result.first();
Assert.equals(20, c2.getWallet().getAmount());
Assert.equals(9, vm2.getCansInMachine().size());
Assert.equals(33, vm2.getStoredCash());
}
}
- Less moving parts
- More reusable
- Simpler
- Easier
- Mocks & Stubs are
gone
“But then it’s an
integration test!”
1. Immutable data
structures are just
values.
2. We have no
business peeking at
a method’s tools;
only its results,
effects
3. Pure functions
are already
deterministic
Case study #3
Essential effects
public interface EmailSender {
void sendEmail(String addr, Email email);
}
public class SpecialOffers {
private final EmailSender sender;
void sendSpecialOffers(Customer c) {
if (!c.isUnsubscribed()) {
String content = "Hi " + c.getName() + "!";
sender.sendEmail(c.getEmailAddr(),
new Email(content))
}
}
}
public class SpecialOffersTest {
EmailSender sender = mock(EmailSender.class)
public testSendEmail() {
SpecialOffers offers = new SpecialOffers(sender);
offers.sendSpecialOffers(
new Customer(false, “Bob”, “foo@foo.com”));
verify(sender).send(“foo@foo.com”,
new Email(“Hi, Bob!”));
}
}
public class SpecialOffersTest {
EmailSender sender = mock(EmailSender.class)
public testSendEmail() {
SpecialOffers offers = new SpecialOffers(sender);
offers.sendSpecialOffers(
new Customer(false, “Bob”, “foo@foo.com”));
verify(sender).send(“foo@foo.com”,
new Email(“Hi, Bob!”));
}
}
Mock
Ok, so it tests we send an
email.
But what is the mock trying
to tell us?
public interface EmailSender {
void sendEmail(String addr, Email email);
}
public class SpecialOffers {
private final EmailSender sender;
void sendSpecialOffers(Customer c) {
if (!c.isUnsubscribed()) {
String content = "Hi " + c.getName() + "!";
sender.sendEmail(c.getEmailAddr(),
new Email(content))
}
}
}
I only care about the intent to
send an email, not the actual
sending. Can the intent be its
own thing?
public interface SendEmailIntent {
String getAddress();
Email getEmail();
}
public interface Interpreter {
void interpret(SendEmailIntent intent);
}
public class SpecialOffers {
Optional<SendEmailIntent> sendSpecialOffers(
Customer c) {
if (!c.isUnsubscribed()) {
String content = "Hi " + c.getName() + "!";
return Optional.of(new SendEmailIntent(
c.getEmailAddr(),
new Email(content)));
} else {
return Optional.empty();
}
}
}
We can have
an
interpreter
elsewhere.
public class SpecialOffersTest {
public testSendEmail() {
SpecialOffers offers = new SpecialOffers();
SendEmailIntent intent = offers.sendSpecialOffers(
new Customer(false, “Bob”,
“foo@foo.com”)).get();
Assert.equals(intent.getAddress(), “foo@foo.com”);
Assert.equals(intent.getEmail().getText(),
“Hi, Bob!”);
}
}
- Separated intent
from execution
- More reusable
- Simpler
- Easier
- Mocks are gone
Mocks kill TDD.
TDD = design
methodology
Test-first
encourages you
to design code
well enough to
test…
…and no further.
Mocks & stubs
set a
looooow bar
This totally
guts TDD’s
value for
design.
Conclusion:
Side effects are
the real killer
All I do is make the
input deterministic. If
the input is already
just immutable values,
then you don’t need
me.
Stub Mock
If you’re just using me
because stuff is hard
to create, you need to
get back and design
harder!
Stub Mock
I make output
deterministic, by
recording method
calls instead of
allowing effects.
Stub Mock
Sometimes, this
means that I test a
pointless web of lies,
that doesn’t touch the
code’s reason for
existence.
Stub Mock
Other times, I am really
testing the intent of the
code, which can be pulled
out as its own structure.
This separates the
concern of choosing the
next thing.
Stub Mock
Stub Mock
If you are using
immutable types and
pure functions, then
you’re home and
hosed.
Forget about
• “collaborators”
• “Tell don’t ask”
• Avoiding static methods
• Avoiding “new”.
Imagine a world without mocks

More Related Content

What's hot

Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with MockitoRichard Paul
 
Hinemosによる初期構築~障害検知自動復旧システムの実現について
Hinemosによる初期構築~障害検知自動復旧システムの実現についてHinemosによる初期構築~障害検知自動復旧システムの実現について
Hinemosによる初期構築~障害検知自動復旧システムの実現についてHinemos
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerToshiaki Maki
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Scott Wlaschin
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기Hosung Lee
 
Pivotal Labs 고객사례 - Coinone
Pivotal Labs 고객사례 - CoinonePivotal Labs 고객사례 - Coinone
Pivotal Labs 고객사례 - CoinoneVMware Tanzu Korea
 
muCon 2016: Authentication in Microservice Systems By David Borsos
muCon 2016: Authentication in Microservice Systems By David BorsosmuCon 2016: Authentication in Microservice Systems By David Borsos
muCon 2016: Authentication in Microservice Systems By David BorsosOpenCredo
 
Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022Sam Brannen
 
Load Testing with k6 framework
Load Testing with k6 frameworkLoad Testing with k6 framework
Load Testing with k6 frameworkSvetlin Nakov
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101정주 김
 
Mka python jr-urok_03_ua_1563258828
Mka python jr-urok_03_ua_1563258828Mka python jr-urok_03_ua_1563258828
Mka python jr-urok_03_ua_1563258828PavloTsiura
 
認証サービスへのWebAuthnの導入
認証サービスへのWebAuthnの導入認証サービスへのWebAuthnの導入
認証サービスへのWebAuthnの導入TakashiTsukamoto4
 
19012011102_Nayan Oza_Practical-7_AI.pdf
19012011102_Nayan Oza_Practical-7_AI.pdf19012011102_Nayan Oza_Practical-7_AI.pdf
19012011102_Nayan Oza_Practical-7_AI.pdfNayanOza
 
Introduction to PowerShell
Introduction to PowerShellIntroduction to PowerShell
Introduction to PowerShellBoulos Dib
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線MeetupMasatoshi Tada
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of CompositionScott Wlaschin
 
決済サービスのSpring Bootのバージョンを2系に上げた話
決済サービスのSpring Bootのバージョンを2系に上げた話決済サービスのSpring Bootのバージョンを2系に上げた話
決済サービスのSpring Bootのバージョンを2系に上げた話Ryosuke Uchitate
 

What's hot (20)

Mocking in Java with Mockito
Mocking in Java with MockitoMocking in Java with Mockito
Mocking in Java with Mockito
 
Hinemosによる初期構築~障害検知自動復旧システムの実現について
Hinemosによる初期構築~障害検知自動復旧システムの実現についてHinemosによる初期構築~障害検知自動復旧システムの実現について
Hinemosによる初期構築~障害検知自動復旧システムの実現について
 
Spring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & MicrometerSpring Boot Actuator 2.0 & Micrometer
Spring Boot Actuator 2.0 & Micrometer
 
Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013Domain Driven Design with the F# type System -- NDC London 2013
Domain Driven Design with the F# type System -- NDC London 2013
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기
 
Pivotal Labs 고객사례 - Coinone
Pivotal Labs 고객사례 - CoinonePivotal Labs 고객사례 - Coinone
Pivotal Labs 고객사례 - Coinone
 
muCon 2016: Authentication in Microservice Systems By David Borsos
muCon 2016: Authentication in Microservice Systems By David BorsosmuCon 2016: Authentication in Microservice Systems By David Borsos
muCon 2016: Authentication in Microservice Systems By David Borsos
 
Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022
 
Load Testing with k6 framework
Load Testing with k6 frameworkLoad Testing with k6 framework
Load Testing with k6 framework
 
파이썬 TDD 101
파이썬 TDD 101파이썬 TDD 101
파이썬 TDD 101
 
Mka python jr-urok_03_ua_1563258828
Mka python jr-urok_03_ua_1563258828Mka python jr-urok_03_ua_1563258828
Mka python jr-urok_03_ua_1563258828
 
認証サービスへのWebAuthnの導入
認証サービスへのWebAuthnの導入認証サービスへのWebAuthnの導入
認証サービスへのWebAuthnの導入
 
Cpp unit
Cpp unit Cpp unit
Cpp unit
 
19012011102_Nayan Oza_Practical-7_AI.pdf
19012011102_Nayan Oza_Practical-7_AI.pdf19012011102_Nayan Oza_Practical-7_AI.pdf
19012011102_Nayan Oza_Practical-7_AI.pdf
 
Introduction to PowerShell
Introduction to PowerShellIntroduction to PowerShell
Introduction to PowerShell
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
 
The Power of Composition
The Power of CompositionThe Power of Composition
The Power of Composition
 
決済サービスのSpring Bootのバージョンを2系に上げた話
決済サービスのSpring Bootのバージョンを2系に上げた話決済サービスのSpring Bootのバージョンを2系に上げた話
決済サービスのSpring Bootのバージョンを2系に上げた話
 
Spring security
Spring securitySpring security
Spring security
 
GMock framework
GMock frameworkGMock framework
GMock framework
 

Similar to Imagine a world without mocks

2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good TestsTomek Kaczanowski
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good TestsTomek Kaczanowski
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42Yevhen Bobrov
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...DroidConTLV
 
Java best practices
Java best practicesJava best practices
Java best practicesRay Toal
 
Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016Danny Preussler
 
An Introduction To CQRS
An Introduction To CQRSAn Introduction To CQRS
An Introduction To CQRSNeil Robbins
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
JAVA...With N.E.T_B.E.A.N.S___________________________________.pdf
JAVA...With N.E.T_B.E.A.N.S___________________________________.pdfJAVA...With N.E.T_B.E.A.N.S___________________________________.pdf
JAVA...With N.E.T_B.E.A.N.S___________________________________.pdfcalderoncasto9163
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql JOYITAKUNDU1
 
Exceptions irst
Exceptions irstExceptions irst
Exceptions irstjkumaranc
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Juan Pablo
 
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"epamspb
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimizedWoody Pewitt
 

Similar to Imagine a world without mocks (20)

2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests2012 JDays Bad Tests Good Tests
2012 JDays Bad Tests Good Tests
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
Griffon @ Svwjug
Griffon @ SvwjugGriffon @ Svwjug
Griffon @ Svwjug
 
The uniform interface is 42
The uniform interface is 42The uniform interface is 42
The uniform interface is 42
 
JavaTalks: OOD principles
JavaTalks: OOD principlesJavaTalks: OOD principles
JavaTalks: OOD principles
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
 
Java best practices
Java best practicesJava best practices
Java best practices
 
Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016Unit testing without Robolectric, Droidcon Berlin 2016
Unit testing without Robolectric, Droidcon Berlin 2016
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
An Introduction To CQRS
An Introduction To CQRSAn Introduction To CQRS
An Introduction To CQRS
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
JAVA...With N.E.T_B.E.A.N.S___________________________________.pdf
JAVA...With N.E.T_B.E.A.N.S___________________________________.pdfJAVA...With N.E.T_B.E.A.N.S___________________________________.pdf
JAVA...With N.E.T_B.E.A.N.S___________________________________.pdf
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql
 
Exceptions irst
Exceptions irstExceptions irst
Exceptions irst
 
Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#Lo Mejor Del Pdc2008 El Futrode C#
Lo Mejor Del Pdc2008 El Futrode C#
 
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
 
Is your C# optimized
Is your C# optimizedIs your C# optimized
Is your C# optimized
 
JavaScript Refactoring
JavaScript RefactoringJavaScript Refactoring
JavaScript Refactoring
 

More from kenbot

Grow your own tech leads
Grow your own tech leadsGrow your own tech leads
Grow your own tech leadskenbot
 
Applied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionalityApplied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionalitykenbot
 
Responsible DI: Ditch the Frameworks
Responsible DI: Ditch the FrameworksResponsible DI: Ditch the Frameworks
Responsible DI: Ditch the Frameworkskenbot
 
FP adoption at REA
FP adoption at REAFP adoption at REA
FP adoption at REAkenbot
 
Lenses for the masses - introducing Goggles
Lenses for the masses - introducing GogglesLenses for the masses - introducing Goggles
Lenses for the masses - introducing Goggleskenbot
 
Good functional programming is good programming
Good functional programming is good programmingGood functional programming is good programming
Good functional programming is good programmingkenbot
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functionskenbot
 
2 Years of Real World FP at REA
2 Years of Real World FP at REA2 Years of Real World FP at REA
2 Years of Real World FP at REAkenbot
 
Your data structures are made of maths!
Your data structures are made of maths!Your data structures are made of maths!
Your data structures are made of maths!kenbot
 
Category theory for beginners
Category theory for beginnersCategory theory for beginners
Category theory for beginnerskenbot
 
The disaster of mutable state
The disaster of mutable stateThe disaster of mutable state
The disaster of mutable statekenbot
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monadskenbot
 

More from kenbot (12)

Grow your own tech leads
Grow your own tech leadsGrow your own tech leads
Grow your own tech leads
 
Applied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionalityApplied category theory: the emerging science of compositionality
Applied category theory: the emerging science of compositionality
 
Responsible DI: Ditch the Frameworks
Responsible DI: Ditch the FrameworksResponsible DI: Ditch the Frameworks
Responsible DI: Ditch the Frameworks
 
FP adoption at REA
FP adoption at REAFP adoption at REA
FP adoption at REA
 
Lenses for the masses - introducing Goggles
Lenses for the masses - introducing GogglesLenses for the masses - introducing Goggles
Lenses for the masses - introducing Goggles
 
Good functional programming is good programming
Good functional programming is good programmingGood functional programming is good programming
Good functional programming is good programming
 
Data made out of functions
Data made out of functionsData made out of functions
Data made out of functions
 
2 Years of Real World FP at REA
2 Years of Real World FP at REA2 Years of Real World FP at REA
2 Years of Real World FP at REA
 
Your data structures are made of maths!
Your data structures are made of maths!Your data structures are made of maths!
Your data structures are made of maths!
 
Category theory for beginners
Category theory for beginnersCategory theory for beginners
Category theory for beginners
 
The disaster of mutable state
The disaster of mutable stateThe disaster of mutable state
The disaster of mutable state
 
Running Free with the Monads
Running Free with the MonadsRunning Free with the Monads
Running Free with the Monads
 

Recently uploaded

%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...masabamasaba
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...chiefasafspells
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...masabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 

Recently uploaded (20)

%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 

Imagine a world without mocks

  • 1. Imagine a world without mocks @KenScambler Scala Developer at
  • 2.
  • 3.
  • 4. Me 14 years 5 years 5 years when possible when bored when forced
  • 6. Q: What’s so bad about mocks & stubs? A: The problem they solve is “how to test poorly designed code”
  • 7. How did we get here?
  • 10. http://martinfowler.com/articles/mocksArentStubs.html Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.
  • 11. UserService User getUser(UserId) If you ask me “authUser(1234)”, I’ll say “true” Stub UserRepo DB Record selectUser(SQL)
  • 12. UserService User getUser(UserId) Stub UserRepo Record selectUser(SQL) UserService’s input is now deterministic! If you ask me “authUser(1234)”, I’ll say “true” DB
  • 13. http://martinfowler.com/articles/mocksArentStubs.html Mocks are objects pre- programmed with expectations which form a specification of the calls they are expected to receive.
  • 14. UserService User getUser(UserId) I expect “selectUser()” to be called once Mock If you ask me “authUser(1234)”, I’ll say “true”
  • 15. UserService User getUser(UserId) I expect “selectUser()” to be called once Mock UserService’s output is now deterministic! If you ask me “authUser(1234)”, I’ll say “true”
  • 17. So far so good.
  • 20. UserService User getUser(UserId) Mock What if an equivalent method is called instead? If you ask me “authUser(1234)”, I’ll say “true” authLocalUser(1234) Stub
  • 22. UserService User getUser(UserId) Honestly, no one’s asked me that before. authLocalUser(1234)
  • 23. UserService User getUser(UserId) I’m just a sock. authLocalUser(1234)
  • 26. UserService User getUser(UserId) IT DIDN’T GET CALLED!!! NOTHING HAPPENED!!!!!
  • 27. UserService User getUser(UserId) IT DIDN’T GET CALLED!!! NOTHING HAPPENED!!!!! Real problem: The stub configuration was out of date.
  • 29. public interface Config { // Database stuff String getDatabaseHost(); int getDatabasePort(); int getMaxThreads(); int getConnectionTimeout(); // Potato settings String getDefaultPotatoVariety(); int getMaxPotatoes(); double getPotatoShininess(); // Sacrificial settings int getBloodSacrificeGoatCount(); int getBloodSacrificeChickenCount(); int getBloodSacrificeSheepCount(); }
  • 30. public class PotatoService { public PotatoService(Config config) { this.potatoVariety = config.getPotatoVariety(); this.maxPotatoes = config.getMaxPotatoes(); } public Salad makePotatoSalad() {...} }
  • 31. public class PotatoServiceTest { Config config = mock(Config.class) @Before public void before() { when(config.getDefaultPotatoVariety()) .thenReturn(“pontiac”); when(config.getMaxPotatoes()) .thenReturn(33); } public testMakeSalad() { PotatoService service = new PotatoService(); Assert.equalTo(service.makeSalad(), ...); } }
  • 32. public class PotatoServiceTest { Config config = mock(Config.class) @Before public void before() { when(config.getDefaultPotatoVariety()) .thenReturn(“pontiac”); when(config.getMaxPotatoes()) .thenReturn(33); } public testMakeSalad() { PotatoService service = new PotatoService(); Assert.equalTo(service.makeSalad(), ...); } } Stub
  • 33. Looks ok. But what is the stub trying to tell us?
  • 34. No-ones ever going to need all those things at once. public interface Config { // Database stuff String getDatabaseHost(); int getDatabasePort(); int getMaxThreads(); int getConnectionTimeout(); // Potato settings String getDefaultPotatoVariety(); int getMaxPotatoes(); double getPotatoShininess(); // Sacrificial settings int getBloodSacrificeGoatCount(); int getBloodSacrificeChickenCount(); int getBloodSacrificeSheepCount(); }
  • 35. That’s better! public interface DatabaseConfig { String getDatabaseHost(); int getDatabasePort(); int getMaxThreads(); int getConnectionTimeout(); } public interface PotatoConfig { String getDefaultPotatoVariety(); int getMaxPotatoes(); double getPotatoShininess(); } public interface SacrificialConfig { int getBloodSacrificeGoatCount(); int getBloodSacrificeChickenCount(); int getBloodSacrificeSheepCount(); }
  • 36. public class PotatoService { public PotatoService(PotatoConfig config) { this.potatoVariety = config.getPotatoVariety(); this.maxPotatoes = config.getMaxPotatoes(); } public Salad makePotatoSalad() {...} } Don’t you just need the two fields? Does it matter where they come from?
  • 37. public class PotatoService { public PotatoService(String variety, int max) { this.potatoVariety = variety; this.maxPotatoes = max; } public Salad makePotatoSalad() {...} } The application wiring can be someone else’s business.
  • 38. public class PotatoServiceTest { public testMakeSalad() { PotatoService service = new PotatoService(“pontiac”, 33); Assert.equalTo(service.makeSalad(), ...); } }
  • 39. - More modular - More reusable - Simpler - Less code - Stubs are gone
  • 40. Case study #2 Unnecessary mutable state
  • 41.
  • 42. public interface Wallet { int removeCoins(int amount); int getAmount(); } public interface VendingMachine { void insertCoins(int amount); Can collectCan(); int getStoredCash(); } public interface Customer { void buyDrink(); }
  • 43. public class CustomerTest { Wallet wallet = mock(Wallet.class); VendingMachine machine = mock(VendingMachine.class); @Before public void before() { when(wallet.removeCoins(3)).thenReturn(3); when(vendingMachine.collectCan()) .thenReturn(new CokeCan()); } public testBuyDrink() { Customer c = new Customer(); c.buyDrink(); verify(wallet).removeCoins(3); verify(vendingMachine).insertCoins(3); verify(vendingMachine).collectCan(); } }
  • 44. public class CustomerTest { Wallet wallet = mock(Wallet.class); VendingMachine machine = mock(VendingMachine.class); @Before public void before() { when(wallet.removeCoins(3)).thenReturn(3); when(vendingMachine.collectCan()) .thenReturn(new CokeCan()); } public testBuyDrink() { Customer c = new Customer(); c.buyDrink(); verify(wallet).removeCoins(3); verify(vendingMachine).insertCoins(3); verify(vendingMachine).collectCan(); } } Stub Mock
  • 45. The class under test is separated now! But what are the mocks telling us?
  • 46. public interface Wallet { int removeCoins(int amount); int getAmount(); } public interface VendingMachine { void insertCoins(int amount); Can collectCan(); int getStoredCash(); } public interface Customer { void buyDrink(); } Surely we care about the resulting state, not the in-betweeny verbs.
  • 47. If the state is just immutable values, we don’t have to force isolation public interface Wallet { int removeCoins(int amount); int getAmount(); } public interface VendingMachine { void insertCoins(int amount); Can collectCan(); int getStoredCash(); } public interface Customer { void buyDrink(); }
  • 48. public interface Wallet { int getAmount(); Wallet removeCoins(int amount); } public interface VendingMachine { Optional<Can> getCanInTray(); int getStoredCash(); List<Can> getCansInMachine(); VendingMachine insertCoins(int amount); VendingMachine collectCan(); } public interface Customer { Wallet getWallet(); List<Can> getCansHeld(); Pair<VendingMachine, Customer> buyDrink(VendingMachine vm); }
  • 49. public interface Wallet { int getAmount(); Wallet removeCoins(int amount); } public interface VendingMachine { Optional<Can> getCanInTray(); int getStoredCash(); List<Can> getCansInMachine(); VendingMachine insertCoins(int amount); VendingMachine collectCan(); } public interface Customer { Wallet getWallet(); List<Can> getCansHeld(); Pair<VendingMachine, Customer> buyDrink(VendingMachine vm); } Immutable state
  • 50. public interface Wallet { int getAmount(); Wallet removeCoins(int amount); } public interface VendingMachine { Optional<Can> getCanInTray(); int getStoredCash(); List<Can> getCansInMachine(); VendingMachine insertCoins(int amount); VendingMachine collectCan(); } public interface Customer { Wallet getWallet(); List<Can> getCansHeld(); Pair<VendingMachine, Customer> buyDrink(VendingMachine vm); } “Actions” just return new copies
  • 51. public class CustomerTest { public testBuyDrink() { Customer c = new Customer(new Wallet(23)); VendingMachine vm = new VendingMachine(10,30); Pair<VendingMachine, Customer> result = c.buyDrink(vm); Customer c2 = result.second(); VendingMachine vm2 = result.first(); Assert.equals(20, c2.getWallet().getAmount()); Assert.equals(9, vm2.getCansInMachine().size()); Assert.equals(33, vm2.getStoredCash()); } }
  • 52. - Less moving parts - More reusable - Simpler - Easier - Mocks & Stubs are gone
  • 53. “But then it’s an integration test!”
  • 54. 1. Immutable data structures are just values.
  • 55. 2. We have no business peeking at a method’s tools; only its results, effects
  • 56. 3. Pure functions are already deterministic
  • 58. public interface EmailSender { void sendEmail(String addr, Email email); } public class SpecialOffers { private final EmailSender sender; void sendSpecialOffers(Customer c) { if (!c.isUnsubscribed()) { String content = "Hi " + c.getName() + "!"; sender.sendEmail(c.getEmailAddr(), new Email(content)) } } }
  • 59. public class SpecialOffersTest { EmailSender sender = mock(EmailSender.class) public testSendEmail() { SpecialOffers offers = new SpecialOffers(sender); offers.sendSpecialOffers( new Customer(false, “Bob”, “foo@foo.com”)); verify(sender).send(“foo@foo.com”, new Email(“Hi, Bob!”)); } }
  • 60. public class SpecialOffersTest { EmailSender sender = mock(EmailSender.class) public testSendEmail() { SpecialOffers offers = new SpecialOffers(sender); offers.sendSpecialOffers( new Customer(false, “Bob”, “foo@foo.com”)); verify(sender).send(“foo@foo.com”, new Email(“Hi, Bob!”)); } } Mock
  • 61. Ok, so it tests we send an email. But what is the mock trying to tell us?
  • 62. public interface EmailSender { void sendEmail(String addr, Email email); } public class SpecialOffers { private final EmailSender sender; void sendSpecialOffers(Customer c) { if (!c.isUnsubscribed()) { String content = "Hi " + c.getName() + "!"; sender.sendEmail(c.getEmailAddr(), new Email(content)) } } } I only care about the intent to send an email, not the actual sending. Can the intent be its own thing?
  • 63. public interface SendEmailIntent { String getAddress(); Email getEmail(); } public interface Interpreter { void interpret(SendEmailIntent intent); } public class SpecialOffers { Optional<SendEmailIntent> sendSpecialOffers( Customer c) { if (!c.isUnsubscribed()) { String content = "Hi " + c.getName() + "!"; return Optional.of(new SendEmailIntent( c.getEmailAddr(), new Email(content))); } else { return Optional.empty(); } } } We can have an interpreter elsewhere.
  • 64. public class SpecialOffersTest { public testSendEmail() { SpecialOffers offers = new SpecialOffers(); SendEmailIntent intent = offers.sendSpecialOffers( new Customer(false, “Bob”, “foo@foo.com”)).get(); Assert.equals(intent.getAddress(), “foo@foo.com”); Assert.equals(intent.getEmail().getText(), “Hi, Bob!”); } }
  • 65. - Separated intent from execution - More reusable - Simpler - Easier - Mocks are gone
  • 68. Test-first encourages you to design code well enough to test…
  • 70. Mocks & stubs set a looooow bar
  • 73. All I do is make the input deterministic. If the input is already just immutable values, then you don’t need me. Stub Mock
  • 74. If you’re just using me because stuff is hard to create, you need to get back and design harder! Stub Mock
  • 75. I make output deterministic, by recording method calls instead of allowing effects. Stub Mock
  • 76. Sometimes, this means that I test a pointless web of lies, that doesn’t touch the code’s reason for existence. Stub Mock
  • 77. Other times, I am really testing the intent of the code, which can be pulled out as its own structure. This separates the concern of choosing the next thing. Stub Mock
  • 78. Stub Mock If you are using immutable types and pure functions, then you’re home and hosed. Forget about • “collaborators” • “Tell don’t ask” • Avoiding static methods • Avoiding “new”.