SlideShare uma empresa Scribd logo
1 de 58
Baixar para ler offline
When TDD Goes Awry
Reggio Emilia - IAD 2013
Clueless tests, infesting
mocks and other horrors...
A voyage into today Java
Enterprise worse practices.

Uberto	
  Barbini

@ramtop


h0ps://github.com/uberto
SHO

to	
  start

SHIN	
  
Heart,	
  mind

In the beginner's mind there are many possibilities,
in the expert's mind there are few.
a·wry (-r)
adv.
1. In a position that is turned or twisted toward one
side; askew.
2. Away from the correct course; amiss.
a·wry (-r)
adv.
1. In a position that is turned or twisted toward one
side; askew.
2. Away from the correct course; amiss.
@Test

public void testGetSwapType_SPOTFWD() {

when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("SWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());




when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("FWDFWDSWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());

}








private void setUpTrade(final String tradingType) {

when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);

when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);

when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);

trade = new Trade(tradeBean);

}
Test Stories
Each test should tell a story

Micro tests develop algorithms

Scenario tests illustrate the design

Test Stories
Each test should tell a story

Micro tests develop algorithms

Scenario tests illustrate the design


When you are thinking big thoughts, write big tests.
When you are thinking little thoughts, write little tests.

!
Kent Beck, Quora
Test Stories
Each test should tell a story

Micro tests develop algorithms

Scenario tests illustrate the design


When you are thinking big thoughts, write big tests.
When you are thinking little thoughts, write little tests.

!
Kent Beck, Quora

Objects are nouns. Methods are verb. Good
design is a good story. A good test remind us of a
good design. 

Do you remember XP Metaphor?
2001
My first project

2001
My first project

2001
Meaningful test names
12 years later… and still we are talking about TDD
12 years later… and still we are talking about TDD

Test Driven Design
12 years later… and still we are talking about TDD

Test Driven Design
It’s a kind of design technique, not a way to test.
12 years later… and still we are talking about TDD
I get paid for code that works, not for tests, so
my philosophy is to test as little as possible to
reach a given level of confidence.




Kent Beck Stackoverflow

Test Driven Design
It’s a kind of design technique, not a way to test.
12 years later… and still we are talking about TDD
I get paid for code that works, not for tests, so
my philosophy is to test as little as possible to
reach a given level of confidence.




Kent Beck Stackoverflow

Test Driven Design
It’s a kind of design technique, not a way to test.

When TDD is not useful:
when your don’t care about design

i.e.. technical spikes, learning exercises
Question:

Why designing for testability result
in good design?
The caveman house design

Carlo Pescio
Question:

Why designing for testability result
in good design?
The caveman house design

Carlo Pescio

Global state
Hidden dependencies
Inflexible behaviour

Things that work together
are kept close

@Test

public void testGetSwapType_SPOTFWD() {

when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("SWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());




when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("FWDFWDSWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());

}








private void setUpTrade(final String tradingType) {

when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);

when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);

when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);

trade = new Trade(tradeBean);

}
@Test

public void testGetSwapType_SPOTFWD() {

when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("SWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());




when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("FWDFWDSWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());

}








private void setUpTrade(final String tradingType) {

when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);

when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);

when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);

trade = new Trade(tradeBean);

}

If to test 3 lines of simple code, we have
10 lines of complicated test…

!

Which is more likely to have a bug? the
code or the test?
Bad test smells: 1 - Too many assertions

Let’s start from Assertions
One of the least followed TDD rule says: “There must be
one assertion for test”. Why?
Bad test smells: 1 - Too many assertions

Let’s start from Assertions
One of the least followed TDD rule says: “There must be
one assertion for test”. Why?
The point behind testing one thing at time is the we want to
run all the state checks, every time, independently.
!

No logic in the tests, not even an “if”.
!




As less as possible duplication with the logic being tested,
ideally no duplication with other tests.

Bad test smells: 1 - Too many assertions

Let’s start from Assertions
One of the least followed TDD rule says: “There must be
one assertion for test”. Why?
The point behind testing one thing at time is the we want to
run all the state checks, every time, independently.
!

No logic in the tests, not even an “if”.
!

As less as possible duplication with the logic being tested,
ideally no duplication with other tests.




There are 3 kinds of multiple assertions:
Multi Assertion I

@Test

public void splitInWords() throws Exception {




String text = "To be, or not to be: that is the question";

String[] words = getWords(text);




//these assertion are increasing the precision, 

//if one fails it makes no sense to run the next

assertNotNull(words);




assertTrue(words.length > 0);

assertEquals("To", words[0]);




assertEquals(10, words.length);

assertEquals("question", words[9]);




}

private String[] getWords(String s) {

return s.split(" ");

}
Multi Assertion I

@Test

public void splitInWords() throws Exception {




String text = "To be, or not to be: that is the question";

String[] words = getWords(text);




//these assertion are increasing the precision, 

//if one fails it makes no sense to run the next

assertNotNull(words);




assertTrue(words.length > 0);

assertEquals("To", words[0]);




assertEquals(10, words.length);

assertEquals("question", words[9]);

}




private String[] getWords(String s) {

return s.split(" ");

}

Sometimes scenario tests
use assertions in this way
Multi Assertion II



@Test

public void calculateQuote() throws Exception {




Quote expected = new Quote("USDGBP", "0.62");




Quote calculated = getQuote("USD", "GBP");





//no very good because if one fail we don't know the value of the other check

assertEquals(expected.getSubject(), calculated.getSubject());

assertEquals(expected.getValue(), calculated.getValue());

//much better because it compare all fields every time

assertThat(expected, sameQuote(calculated));

}







private Matcher<Quote> sameQuote(Quote quote) {

return new QuoteMatcher(quote);

}





private Quote getQuote(String cur1, String cur2) {

return new Quote(cur1+cur2, "0.62");

}
Multi Assertion III
@Test

public void commutativeProperty() throws Exception {




//these three should be put on 3 different tests

//or use some kind of data table assertions like spec

//or maybe assertAndContinue()







assertEquals(5, sum(3,2));

assertEquals(8, sum(3,5));

assertEquals(sum(3,sum(4,5)), sum(sum(3, 4),5));

}

Bad test smells: 2 - Too many doubles

Stubs
Mocks test behaviour, Stubs test state
!

Stubs doesn’t verify calls
!

Stubs doesn’t check for parameters
!

Stubs can be easily reused. Different examples.
!

No need to create stubs dynamically.
!

No need to use doubles at all for immutables.
Mocks
Mocks are complicated, try to use them scarcely.
!

Use stubs for decorators and close friends,
mocks for external collaborators (i.e. listeners)
!

Stubs can be prepared in setup. Mocks must be
“loaded” in the actual test.
!

Try to verify mocks with actual params or matcher,
not any (or maybe you wanted a stub instead?).
Smells: Assertions + Mocks
@Test

public void testGetSwapType_SPOTFWD() {

when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("SWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());




when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

setUpTrade("FWDFWDSWAP");

assertEquals(TradeType.SPOTFWD, trade.getType());

}








private void setUpTrade(final String tradingType) {

when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);

when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);

when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);

trade = new Trade(tradeBean);

}
Split and inline
@Test

public void testGetSwapType_SPOTFWD_SWP() {

when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);

when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);

when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn("SWAP");

trade = new Trade(tradeBean);

assertEquals(TradeType.SPOTFWD, trade.getType());

}




@Test

public void testGetSwapType_SPOTFWD_FWDSWP() {

when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");

when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);

when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);

when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn("FWDFWDSWAP");

trade = new Trade(tradeBean);

assertEquals(TradeType.SPOTFWD, trade.getType());

}

!
Stubs with builders
@Test

public void useSwapTypeIfTradingIsSwap() {

//split test in two

//construct concrete bean using a fluent builder

tradeBean = SimpleTradeBean.prepare().currencies("EURGBP",
"0.67").swapType("SPOTFWD").tradingType("SWAP");


Bean is mutable




trade = new Trade(tradeBean);




//next step: better using a matcher on an expected Trade rather than 

// compare a field at time

assertEquals(TradeType.SPOTFWD, trade.getType());

}




@Test

public void useSwapTypeIfTradingIsFwdSwap() {

tradeBean = SimpleTradeBean.prepare().currencies("USDGBP",
"1.2").swapType("SPOTFWD").tradingType("FWDSWAP");




trade = new Trade(tradeBean);






assertEquals(TradeType.SPOTFWD, trade.getType());

}
High Coupled Design
@Test

public void testBusSourceSendMessage() throws Exception {




//complex setup, unclear design, high coupling

when(mySource.createActivePublisher(any(String.class),
any(DataFetcher.class))).thenReturn(myPub);

when(myPub.getMessageFactory()).thenReturn(myMsgFactory);

when(myMsgFactory.createMessage("EURUSD")).thenReturn(myMsg);




myFetcher = new DataFetcher(mySource);




mySource.createActivePublisher("quotes", myFetcher);




//why mocking a immutable object?

MessageItem item = mock(MessageItem.class);




when(item.getSubject()).thenReturn("EURUSD");




//7 lines of mocks to test 3 lines of code

myFetcher.updateData(item);




//hard to understand the goal of this test from the verify

verify(mySource).notify(myMsg);

}

!
Bad test smells: 3 - High Coupling

High Coupling

!
!
!
!
!
In software engineering, coupling or dependency is the degree to which
each program module relies on each one of the other modules.
antipattern of high coupling:
!
cohesion refers to the degree to which the elements of a module belong
together.[1] Thus, it is a measure of how strongly-related each piece of
functionality expressed by the source code of a software module is. 






Wikipedia
The usual culprit:
Dependency Injection frameworks
The best classes in any application are the ones that do stuff: the
BarcodeDecoder, the KoopaPhysicsEngine, and theAudioStreamer. These
classes have dependencies; perhaps a BarcodeCameraFinder,
DefaultPhysicsEngine, and an HttpStreamer.!
To contrast, the worst classes in any application are the ones that take up space
without doing much at all: theBarcodeDecoderFactory, the
CameraServiceLoader, and the MutableContextWrapper. These classes are
the clumsy duct tape that wires the interesting stuff together.!
Dagger is a replacement for these FactoryFactory classes. It allows you to focus
on the interesting classes. Declare dependencies, specify how to satisfy them, and
ship your app.!

!
from Dagger introduction!
http://square.github.io/dagger/

Good things about Dagger: 

good and invisible duct tape
I beg to differ, 

duct tape is important!
I beg to differ, 

duct tape is important!
That is, it’s important to
wiring up our objects 

in the best possible way.
!

Write tests to show how
your wiring is done
!

Replace Duct Tape with
Demeter
High Coupled
@Test

public void testBusSourceSendMessage() throws Exception {




//complex setup, unclear design, high coupling

when(mySource.createActivePublisher(any(String.class),
any(DataFetcher.class))).thenReturn(myPub);

when(myPub.getMessageFactory()).thenReturn(myMsgFactory);

when(myMsgFactory.createMessage("EURUSD")).thenReturn(myMsg);




myFetcher = new DataFetcher(mySource);




mySource.createActivePublisher("quotes", myFetcher);




//why mocking a immutable object?

MessageItem item = mock(MessageItem.class);




when(item.getSubject()).thenReturn("EURUSD");




//7 lines of mocks to test 3 lines of code

myFetcher.updateData(item);




//hard to understand the goal of this test from the verify

verify(mySource).notify(myMsg);

}

!
Unmock it with a simpler object
@Test

public void simplifiedBusSourceSendMessage() throws Exception {

//simplify the real class to use it in tests

BusSource mySource = new SimpleBusSource();




myFetcher = new DataFetcher(mySource);




Publisher myPub = mySource.createActivePublisher("quotes", myFetcher);









// myFetcher.updateData(item);

//verify(mySource).notify(myMsg);

//we cannot yet verify the fetcher, so we copied fetcher code here and test it

myMsg = myPub.getMessageFactory().createMessage("EURGBP");

assertEquals("EURGBP", myMsg.getId());





}

!
!
Unmock it with a simpler object
@Test

public void simplifiedBusSourceSendMessage() throws Exception {

//simplify the real class to use it in tests

BusSource mySource = new SimpleBusSource();




myFetcher = new DataFetcher(mySource);




Publisher myPub = mySource.createActivePublisher("quotes", myFetcher);









// myFetcher.updateData(item);

//verify(mySource).notify(myMsg);

//we cannot yet verify the fetcher, so we copied fetcher code here and test it

myMsg = myPub.getMessageFactory().createMessage("EURGBP");

assertEquals("EURGBP", myMsg.getId());





}

!
!
Test with a listener mock
@Test

public void whenUpdateSendMessageToListeners() throws Exception {




Quote eurusd = new Quote("EURUSD", "1.2");




//Simplified BusSource. More complex versions can exist for reporting, etc.

mySource = new SimpleBusSource();




myFetcher = new DataFetcher(mySource);




//let's register a listener for all topics

//this is the only mock, at the end of the chain of real objects

// working together

mySource.addTopicListener("*", myListener);




//when there is an update on data...

myFetcher.updateData(eurusd);




//we check same data arrives to interested listeners

verify(myListener).refresh(argThat(new SamePayload(eurusd)) );

}
Testing Layers
@Test

public void retrieveModules() throws Exception {

Page page = new Page();

Repository repo = mock(Repository.class);

UserData context = new UserData("gb");




//first let's get the page layout for the user country in a parsed xml

MapOfString pageDescriptor = repo.getPageDescriptor(context.getCountry());



//then get the id of actual modules needed matching user context with page layout

List<String> moduleIds = page.selectModules(context, pageDescriptor);




//get the modules as string properties from parsed xml

List<MapOfString> modules = repo.getModules(moduleIds);




//to be safe we need to make sure we are using same stub in this test and the next

assertEquals(STUB_MODULES, modules);

}

@Test

public void composePage() throws Exception {

//here we continue the flow from the previous test

Page page = new Page();




//get the modules as string properties from parsed xml

List<MapOfString> modules = STUB_MODULES;




//compose json page from properties

String jsonPage = page.compose(modules);




assertEquals(expectedJson, jsonPage);

}

Lasagna Code

There is no problem in computer science that cannot be
solved by adding another layer of indirection, except
having too many layers of indirection
Bad test smells: 4 - Complicated Tests
Bad test smells: 4 - Complicated Tests

We have a problem, 

Our code is too difficult to test
Bad test smells: 4 - Complicated Tests

We have a problem, 

Our code is too difficult to test
Let's write a framework to test it!
Bad test smells: 4 - Complicated Tests

We have a problem, 

Our code is too difficult to test
Let's write a framework to test it!
Ok, now we have 2 problems...
Bad test smells: 4 - Complicated Tests

We have a problem, 

Our code is too difficult to test
Let's write a framework to test it!
Ok, now we have 2 problems...

Dedicated test stub must be simple and transparent.

They should explain the model, not hide it.
Bad test smells: 4 - Complicated Tests

We have a problem, 

Our code is too difficult to test
Let's write a framework to test it!
Ok, now we have 2 problems...
Same problem for who has to develop against a
big framework: even if I have the framework tests,
how can I be sure of not losing pieces around?
Let's model domain simply as whole and then split
it up for the framework.

Dedicated test stub must be simple and transparent.

They should explain the model, not hide it.
Testing Layers separately
@Test

public void retrieveModules() throws Exception {

Page page = new Page();

Repository repo = mock(Repository.class);

UserData context = new UserData("gb");




//first let's get the page layout for the user country in a parsed xml

MapOfString pageDescriptor = repo.getPageDescriptor(context.getCountry());



//then get the id of actual modules needed matching user context with page layout

List<String> moduleIds = page.selectModules(context, pageDescriptor);




//get the modules as string properties from parsed xml

List<MapOfString> modules = repo.getModules(moduleIds);




//to be safe we need to make sure we are using same stub in this test and the next

assertEquals(STUB_MODULES, modules);

}

@Test

public void composePage() throws Exception {

//here we continue the flow from the previous test

Page page = new Page();




//get the modules as string properties from parsed xml

List<MapOfString> modules = STUB_MODULES;




//compose json page from properties

String jsonPage = page.compose(modules);




assertEquals(expectedJson, jsonPage);

}

Testing Layers together
@Test

public void composePage() throws Exception {

//we can use a single test here from xml to json




//only mock Repository, because implementation is in another sub-project

Repository repo = mock(Repository.class);

when(repo.getLayoutPage(COUNTRY)).thenReturn(LAYOUT_XML);

when(repo.getModules(MODULE_IDS)).thenReturn(MODULES_XML);




UserData context = new UserData(COUNTRY);




//instead of MapOfStrings we use a proper object to keep layout

Layout page = Layout.buildFromXml(repo.getLayoutPage(context.getCountry()));




//we use Module object to keep module properties and methods

List<Module> moduleList = page.prepareModules(repo, context);




//render the list of modules, easier than with strings properties

String jsonPage = renderer.toJson(moduleList);




//checking matcher

assertThat(EXPECTED_JSON, sameJson(jsonPage));

}
How to improve
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
Ask to new team members or dev from other
teams their impressions.
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
Ask to new team members or dev from other
teams their impressions.
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
Ask to new team members or dev from other
teams their impressions.
Experiment and share.
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
Ask to new team members or dev from other
teams their impressions.
Experiment and share.
How to improve
If your tests give you pain don't ignore it. Localise
the cause.
Ask to new team members or dev from other
teams their impressions.
Experiment and share.
Rule 0: TDD is supposed to be fun and simple.

Mais conteúdo relacionado

Destaque

Se “Embrace Change” è difficile.
Se “Embrace Change” è difficile.Se “Embrace Change” è difficile.
Se “Embrace Change” è difficile.Fabio Mora
 
Lean anche io! No tu no! - Italian Agile Days 2013
Lean anche io! No tu no! - Italian Agile Days 2013Lean anche io! No tu no! - Italian Agile Days 2013
Lean anche io! No tu no! - Italian Agile Days 2013Andrea Scavolini
 
Instilling Scrum Workshop
Instilling Scrum WorkshopInstilling Scrum Workshop
Instilling Scrum WorkshopRaoul Buzziol
 
Agile requirements - alla ricerca del filo rosso (iad 2013)
Agile requirements - alla ricerca del filo rosso (iad 2013)Agile requirements - alla ricerca del filo rosso (iad 2013)
Agile requirements - alla ricerca del filo rosso (iad 2013)Fabio Armani
 
Agileday Coderetreat 2013
Agileday Coderetreat 2013Agileday Coderetreat 2013
Agileday Coderetreat 2013Gabriele Lana
 
From Vision To Product
From Vision To ProductFrom Vision To Product
From Vision To ProductStefano Leli
 

Destaque (9)

Se “Embrace Change” è difficile.
Se “Embrace Change” è difficile.Se “Embrace Change” è difficile.
Se “Embrace Change” è difficile.
 
TDD anche su iOS
TDD anche su iOSTDD anche su iOS
TDD anche su iOS
 
Lean anche io! No tu no! - Italian Agile Days 2013
Lean anche io! No tu no! - Italian Agile Days 2013Lean anche io! No tu no! - Italian Agile Days 2013
Lean anche io! No tu no! - Italian Agile Days 2013
 
Instilling Scrum Workshop
Instilling Scrum WorkshopInstilling Scrum Workshop
Instilling Scrum Workshop
 
Agile requirements - alla ricerca del filo rosso (iad 2013)
Agile requirements - alla ricerca del filo rosso (iad 2013)Agile requirements - alla ricerca del filo rosso (iad 2013)
Agile requirements - alla ricerca del filo rosso (iad 2013)
 
Agileday Coderetreat 2013
Agileday Coderetreat 2013Agileday Coderetreat 2013
Agileday Coderetreat 2013
 
La salute del software
La salute del softwareLa salute del software
La salute del software
 
From Vision To Product
From Vision To ProductFrom Vision To Product
From Vision To Product
 
Bravi si diventa
Bravi si diventaBravi si diventa
Bravi si diventa
 

Semelhante a When Tdd Goes Awry (IAD 2013)

Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)vilniusjug
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentAll Things Open
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Knowvilniusjug
 
Roy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible MistakesRoy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible MistakesRoy Osherove
 
Developer Tests - Things to Know
Developer Tests - Things to KnowDeveloper Tests - Things to Know
Developer Tests - Things to KnowVaidas Pilkauskas
 
New Ideas for Old Code - Greach
New Ideas for Old Code - GreachNew Ideas for Old Code - Greach
New Ideas for Old Code - GreachHamletDRC
 
An Introduction to unit testing
An Introduction to unit testingAn Introduction to unit testing
An Introduction to unit testingSteven Casey
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctlyDror Helper
 
2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easierChristian Hujer
 
TDD and Simple Design Workshop - Session 1 - March 2019
TDD and Simple Design Workshop - Session 1 - March 2019TDD and Simple Design Workshop - Session 1 - March 2019
TDD and Simple Design Workshop - Session 1 - March 2019Paulo Clavijo
 
Open source bridge testing antipatterns presentation
Open source bridge testing antipatterns presentationOpen source bridge testing antipatterns presentation
Open source bridge testing antipatterns presentationmmrobins
 
What NOT to test in your project
What NOT to test in your projectWhat NOT to test in your project
What NOT to test in your projectalexandre freire
 
DSR Testing (Part 1)
DSR Testing (Part 1)DSR Testing (Part 1)
DSR Testing (Part 1)Steve Upton
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Gianluca Padovani
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Dror Helper
 

Semelhante a When Tdd Goes Awry (IAD 2013) (20)

Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)Developer Tests - Things to Know (Vilnius JUG)
Developer Tests - Things to Know (Vilnius JUG)
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Know
 
Testing smells
Testing smellsTesting smells
Testing smells
 
Roy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible MistakesRoy Osherove on Unit Testing Good Practices and Horrible Mistakes
Roy Osherove on Unit Testing Good Practices and Horrible Mistakes
 
Developer Tests - Things to Know
Developer Tests - Things to KnowDeveloper Tests - Things to Know
Developer Tests - Things to Know
 
New Ideas for Old Code - Greach
New Ideas for Old Code - GreachNew Ideas for Old Code - Greach
New Ideas for Old Code - Greach
 
An Introduction to unit testing
An Introduction to unit testingAn Introduction to unit testing
An Introduction to unit testing
 
Building unit tests correctly
Building unit tests correctlyBuilding unit tests correctly
Building unit tests correctly
 
2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier
 
TDD and Simple Design Workshop - Session 1 - March 2019
TDD and Simple Design Workshop - Session 1 - March 2019TDD and Simple Design Workshop - Session 1 - March 2019
TDD and Simple Design Workshop - Session 1 - March 2019
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Open source bridge testing antipatterns presentation
Open source bridge testing antipatterns presentationOpen source bridge testing antipatterns presentation
Open source bridge testing antipatterns presentation
 
B D D Intro
B D D  IntroB D D  Intro
B D D Intro
 
What NOT to test in your project
What NOT to test in your projectWhat NOT to test in your project
What NOT to test in your project
 
DSR Testing (Part 1)
DSR Testing (Part 1)DSR Testing (Part 1)
DSR Testing (Part 1)
 
Testacular
TestacularTestacular
Testacular
 
Tdd is not about testing (OOP)
Tdd is not about testing (OOP)Tdd is not about testing (OOP)
Tdd is not about testing (OOP)
 
TDD and Getting Paid
TDD and Getting PaidTDD and Getting Paid
TDD and Getting Paid
 
Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013Building unit tests correctly with visual studio 2013
Building unit tests correctly with visual studio 2013
 

Mais de Uberto Barbini

CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin Uberto Barbini
 
It's All About Morphisms
It's All About MorphismsIt's All About Morphisms
It's All About MorphismsUberto Barbini
 
The Role of Testing in DevOps
The Role of Testing in DevOpsThe Role of Testing in DevOps
The Role of Testing in DevOpsUberto Barbini
 
Boost your-oop-with-fp
Boost your-oop-with-fpBoost your-oop-with-fp
Boost your-oop-with-fpUberto Barbini
 
Develop Gwt application in TDD
Develop Gwt application in TDDDevelop Gwt application in TDD
Develop Gwt application in TDDUberto Barbini
 

Mais de Uberto Barbini (9)

CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin CQRS with Event Source in Functional sauce served by Kotlin
CQRS with Event Source in Functional sauce served by Kotlin
 
Go kotlin, Go!
Go kotlin, Go!Go kotlin, Go!
Go kotlin, Go!
 
It's All About Morphisms
It's All About MorphismsIt's All About Morphisms
It's All About Morphisms
 
Legacy is Good
Legacy is GoodLegacy is Good
Legacy is Good
 
The Role of Testing in DevOps
The Role of Testing in DevOpsThe Role of Testing in DevOps
The Role of Testing in DevOps
 
When Tdd Goes Awry
When Tdd Goes AwryWhen Tdd Goes Awry
When Tdd Goes Awry
 
Boost your-oop-with-fp
Boost your-oop-with-fpBoost your-oop-with-fp
Boost your-oop-with-fp
 
The Effective Team
The Effective TeamThe Effective Team
The Effective Team
 
Develop Gwt application in TDD
Develop Gwt application in TDDDevelop Gwt application in TDD
Develop Gwt application in TDD
 

Último

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 

Último (20)

The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 

When Tdd Goes Awry (IAD 2013)

  • 1. When TDD Goes Awry Reggio Emilia - IAD 2013 Clueless tests, infesting mocks and other horrors... A voyage into today Java Enterprise worse practices. Uberto  Barbini
 @ramtop
 h0ps://github.com/uberto
  • 2. SHO
 to  start SHIN   Heart,  mind In the beginner's mind there are many possibilities, in the expert's mind there are few.
  • 3. a·wry (-r) adv. 1. In a position that is turned or twisted toward one side; askew. 2. Away from the correct course; amiss.
  • 4. a·wry (-r) adv. 1. In a position that is turned or twisted toward one side; askew. 2. Away from the correct course; amiss. @Test
 public void testGetSwapType_SPOTFWD() {
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("SWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("FWDFWDSWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
 
 
 
 private void setUpTrade(final String tradingType) {
 when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);
 when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);
 when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);
 trade = new Trade(tradeBean);
 }
  • 5. Test Stories Each test should tell a story
 Micro tests develop algorithms
 Scenario tests illustrate the design

  • 6. Test Stories Each test should tell a story
 Micro tests develop algorithms
 Scenario tests illustrate the design
 When you are thinking big thoughts, write big tests. When you are thinking little thoughts, write little tests. ! Kent Beck, Quora
  • 7. Test Stories Each test should tell a story
 Micro tests develop algorithms
 Scenario tests illustrate the design
 When you are thinking big thoughts, write big tests. When you are thinking little thoughts, write little tests. ! Kent Beck, Quora Objects are nouns. Methods are verb. Good design is a good story. A good test remind us of a good design. 
 Do you remember XP Metaphor?
  • 11. 12 years later… and still we are talking about TDD
  • 12. 12 years later… and still we are talking about TDD Test Driven Design
  • 13. 12 years later… and still we are talking about TDD Test Driven Design It’s a kind of design technique, not a way to test.
  • 14. 12 years later… and still we are talking about TDD I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence.
 
 Kent Beck Stackoverflow Test Driven Design It’s a kind of design technique, not a way to test.
  • 15. 12 years later… and still we are talking about TDD I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence.
 
 Kent Beck Stackoverflow Test Driven Design It’s a kind of design technique, not a way to test. When TDD is not useful: when your don’t care about design
 i.e.. technical spikes, learning exercises
  • 16. Question:
 Why designing for testability result in good design? The caveman house design
 Carlo Pescio
  • 17. Question:
 Why designing for testability result in good design? The caveman house design
 Carlo Pescio Global state Hidden dependencies Inflexible behaviour Things that work together are kept close

  • 18. @Test
 public void testGetSwapType_SPOTFWD() {
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("SWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("FWDFWDSWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
 
 
 
 private void setUpTrade(final String tradingType) {
 when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);
 when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);
 when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);
 trade = new Trade(tradeBean);
 }
  • 19. @Test
 public void testGetSwapType_SPOTFWD() {
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("SWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("FWDFWDSWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
 
 
 
 private void setUpTrade(final String tradingType) {
 when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);
 when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);
 when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);
 trade = new Trade(tradeBean);
 } If to test 3 lines of simple code, we have 10 lines of complicated test…
 ! Which is more likely to have a bug? the code or the test?
  • 20. Bad test smells: 1 - Too many assertions Let’s start from Assertions One of the least followed TDD rule says: “There must be one assertion for test”. Why?
  • 21. Bad test smells: 1 - Too many assertions Let’s start from Assertions One of the least followed TDD rule says: “There must be one assertion for test”. Why? The point behind testing one thing at time is the we want to run all the state checks, every time, independently. ! No logic in the tests, not even an “if”. ! 
 As less as possible duplication with the logic being tested, ideally no duplication with other tests.

  • 22. Bad test smells: 1 - Too many assertions Let’s start from Assertions One of the least followed TDD rule says: “There must be one assertion for test”. Why? The point behind testing one thing at time is the we want to run all the state checks, every time, independently. ! No logic in the tests, not even an “if”. ! As less as possible duplication with the logic being tested, ideally no duplication with other tests.
 
 There are 3 kinds of multiple assertions:
  • 23. Multi Assertion I @Test
 public void splitInWords() throws Exception {
 
 String text = "To be, or not to be: that is the question";
 String[] words = getWords(text);
 
 //these assertion are increasing the precision, 
 //if one fails it makes no sense to run the next
 assertNotNull(words);
 
 assertTrue(words.length > 0);
 assertEquals("To", words[0]);
 
 assertEquals(10, words.length);
 assertEquals("question", words[9]);
 
 }
 private String[] getWords(String s) {
 return s.split(" ");
 }
  • 24. Multi Assertion I @Test
 public void splitInWords() throws Exception {
 
 String text = "To be, or not to be: that is the question";
 String[] words = getWords(text);
 
 //these assertion are increasing the precision, 
 //if one fails it makes no sense to run the next
 assertNotNull(words);
 
 assertTrue(words.length > 0);
 assertEquals("To", words[0]);
 
 assertEquals(10, words.length);
 assertEquals("question", words[9]);
 }
 
 private String[] getWords(String s) {
 return s.split(" ");
 } Sometimes scenario tests use assertions in this way
  • 25. Multi Assertion II 
 @Test
 public void calculateQuote() throws Exception {
 
 Quote expected = new Quote("USDGBP", "0.62");
 
 Quote calculated = getQuote("USD", "GBP");
 
 //no very good because if one fail we don't know the value of the other check
 assertEquals(expected.getSubject(), calculated.getSubject());
 assertEquals(expected.getValue(), calculated.getValue());
 //much better because it compare all fields every time
 assertThat(expected, sameQuote(calculated));
 }
 
 
 private Matcher<Quote> sameQuote(Quote quote) {
 return new QuoteMatcher(quote);
 }
 
 private Quote getQuote(String cur1, String cur2) {
 return new Quote(cur1+cur2, "0.62");
 }
  • 26. Multi Assertion III @Test
 public void commutativeProperty() throws Exception {
 
 //these three should be put on 3 different tests
 //or use some kind of data table assertions like spec
 //or maybe assertAndContinue()
 
 
 assertEquals(5, sum(3,2));
 assertEquals(8, sum(3,5));
 assertEquals(sum(3,sum(4,5)), sum(sum(3, 4),5));
 }

  • 27. Bad test smells: 2 - Too many doubles Stubs Mocks test behaviour, Stubs test state ! Stubs doesn’t verify calls ! Stubs doesn’t check for parameters ! Stubs can be easily reused. Different examples. ! No need to create stubs dynamically. ! No need to use doubles at all for immutables.
  • 28. Mocks Mocks are complicated, try to use them scarcely. ! Use stubs for decorators and close friends, mocks for external collaborators (i.e. listeners) ! Stubs can be prepared in setup. Mocks must be “loaded” in the actual test. ! Try to verify mocks with actual params or matcher, not any (or maybe you wanted a stub instead?).
  • 29. Smells: Assertions + Mocks @Test
 public void testGetSwapType_SPOTFWD() {
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("SWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 setUpTrade("FWDFWDSWAP");
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
 
 
 
 private void setUpTrade(final String tradingType) {
 when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);
 when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);
 when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn(tradingType);
 trade = new Trade(tradeBean);
 }
  • 30. Split and inline @Test
 public void testGetSwapType_SPOTFWD_SWP() {
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);
 when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);
 when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn("SWAP");
 trade = new Trade(tradeBean);
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
 
 @Test
 public void testGetSwapType_SPOTFWD_FWDSWP() {
 when(tradeBean.getField(TradeBeanFields.SWAP_TYPE)).thenReturn("SPOTFWD");
 when(tradeBean.getField(TradeBeanFields.ACCOUNT)).thenReturn(ACCOUNT_VAL);
 when(tradeBean.getField(TradeBeanFields.PRICE)).thenReturn(PRICE);
 when(tradeBean.getField(TradeBeanFields.TRADING_TYPE)).thenReturn("FWDFWDSWAP");
 trade = new Trade(tradeBean);
 assertEquals(TradeType.SPOTFWD, trade.getType());
 } !
  • 31. Stubs with builders @Test
 public void useSwapTypeIfTradingIsSwap() {
 //split test in two
 //construct concrete bean using a fluent builder
 tradeBean = SimpleTradeBean.prepare().currencies("EURGBP", "0.67").swapType("SPOTFWD").tradingType("SWAP");
 Bean is mutable 
 trade = new Trade(tradeBean);
 
 //next step: better using a matcher on an expected Trade rather than 
 // compare a field at time
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
 
 @Test
 public void useSwapTypeIfTradingIsFwdSwap() {
 tradeBean = SimpleTradeBean.prepare().currencies("USDGBP", "1.2").swapType("SPOTFWD").tradingType("FWDSWAP");
 
 trade = new Trade(tradeBean);
 
 
 assertEquals(TradeType.SPOTFWD, trade.getType());
 }
  • 32. High Coupled Design @Test
 public void testBusSourceSendMessage() throws Exception {
 
 //complex setup, unclear design, high coupling
 when(mySource.createActivePublisher(any(String.class), any(DataFetcher.class))).thenReturn(myPub);
 when(myPub.getMessageFactory()).thenReturn(myMsgFactory);
 when(myMsgFactory.createMessage("EURUSD")).thenReturn(myMsg);
 
 myFetcher = new DataFetcher(mySource);
 
 mySource.createActivePublisher("quotes", myFetcher);
 
 //why mocking a immutable object?
 MessageItem item = mock(MessageItem.class);
 
 when(item.getSubject()).thenReturn("EURUSD");
 
 //7 lines of mocks to test 3 lines of code
 myFetcher.updateData(item);
 
 //hard to understand the goal of this test from the verify
 verify(mySource).notify(myMsg);
 } !
  • 33. Bad test smells: 3 - High Coupling High Coupling ! ! ! ! ! In software engineering, coupling or dependency is the degree to which each program module relies on each one of the other modules. antipattern of high coupling: ! cohesion refers to the degree to which the elements of a module belong together.[1] Thus, it is a measure of how strongly-related each piece of functionality expressed by the source code of a software module is. 
 
 
 Wikipedia
  • 34. The usual culprit: Dependency Injection frameworks The best classes in any application are the ones that do stuff: the BarcodeDecoder, the KoopaPhysicsEngine, and theAudioStreamer. These classes have dependencies; perhaps a BarcodeCameraFinder, DefaultPhysicsEngine, and an HttpStreamer.! To contrast, the worst classes in any application are the ones that take up space without doing much at all: theBarcodeDecoderFactory, the CameraServiceLoader, and the MutableContextWrapper. These classes are the clumsy duct tape that wires the interesting stuff together.! Dagger is a replacement for these FactoryFactory classes. It allows you to focus on the interesting classes. Declare dependencies, specify how to satisfy them, and ship your app.! ! from Dagger introduction! http://square.github.io/dagger/ Good things about Dagger: 
 good and invisible duct tape
  • 35. I beg to differ, 
 duct tape is important!
  • 36. I beg to differ, 
 duct tape is important! That is, it’s important to wiring up our objects 
 in the best possible way. ! Write tests to show how your wiring is done ! Replace Duct Tape with Demeter
  • 37. High Coupled @Test
 public void testBusSourceSendMessage() throws Exception {
 
 //complex setup, unclear design, high coupling
 when(mySource.createActivePublisher(any(String.class), any(DataFetcher.class))).thenReturn(myPub);
 when(myPub.getMessageFactory()).thenReturn(myMsgFactory);
 when(myMsgFactory.createMessage("EURUSD")).thenReturn(myMsg);
 
 myFetcher = new DataFetcher(mySource);
 
 mySource.createActivePublisher("quotes", myFetcher);
 
 //why mocking a immutable object?
 MessageItem item = mock(MessageItem.class);
 
 when(item.getSubject()).thenReturn("EURUSD");
 
 //7 lines of mocks to test 3 lines of code
 myFetcher.updateData(item);
 
 //hard to understand the goal of this test from the verify
 verify(mySource).notify(myMsg);
 } !
  • 38. Unmock it with a simpler object @Test
 public void simplifiedBusSourceSendMessage() throws Exception {
 //simplify the real class to use it in tests
 BusSource mySource = new SimpleBusSource();
 
 myFetcher = new DataFetcher(mySource);
 
 Publisher myPub = mySource.createActivePublisher("quotes", myFetcher);
 
 
 
 // myFetcher.updateData(item);
 //verify(mySource).notify(myMsg);
 //we cannot yet verify the fetcher, so we copied fetcher code here and test it
 myMsg = myPub.getMessageFactory().createMessage("EURGBP");
 assertEquals("EURGBP", myMsg.getId());
 
 } ! !
  • 39. Unmock it with a simpler object @Test
 public void simplifiedBusSourceSendMessage() throws Exception {
 //simplify the real class to use it in tests
 BusSource mySource = new SimpleBusSource();
 
 myFetcher = new DataFetcher(mySource);
 
 Publisher myPub = mySource.createActivePublisher("quotes", myFetcher);
 
 
 
 // myFetcher.updateData(item);
 //verify(mySource).notify(myMsg);
 //we cannot yet verify the fetcher, so we copied fetcher code here and test it
 myMsg = myPub.getMessageFactory().createMessage("EURGBP");
 assertEquals("EURGBP", myMsg.getId());
 
 } ! !
  • 40. Test with a listener mock @Test
 public void whenUpdateSendMessageToListeners() throws Exception {
 
 Quote eurusd = new Quote("EURUSD", "1.2");
 
 //Simplified BusSource. More complex versions can exist for reporting, etc.
 mySource = new SimpleBusSource();
 
 myFetcher = new DataFetcher(mySource);
 
 //let's register a listener for all topics
 //this is the only mock, at the end of the chain of real objects
 // working together
 mySource.addTopicListener("*", myListener);
 
 //when there is an update on data...
 myFetcher.updateData(eurusd);
 
 //we check same data arrives to interested listeners
 verify(myListener).refresh(argThat(new SamePayload(eurusd)) );
 }
  • 41. Testing Layers @Test
 public void retrieveModules() throws Exception {
 Page page = new Page();
 Repository repo = mock(Repository.class);
 UserData context = new UserData("gb");
 
 //first let's get the page layout for the user country in a parsed xml
 MapOfString pageDescriptor = repo.getPageDescriptor(context.getCountry()); 
 //then get the id of actual modules needed matching user context with page layout
 List<String> moduleIds = page.selectModules(context, pageDescriptor);
 
 //get the modules as string properties from parsed xml
 List<MapOfString> modules = repo.getModules(moduleIds);
 
 //to be safe we need to make sure we are using same stub in this test and the next
 assertEquals(STUB_MODULES, modules);
 }
 @Test
 public void composePage() throws Exception {
 //here we continue the flow from the previous test
 Page page = new Page();
 
 //get the modules as string properties from parsed xml
 List<MapOfString> modules = STUB_MODULES;
 
 //compose json page from properties
 String jsonPage = page.compose(modules);
 
 assertEquals(expectedJson, jsonPage);
 }

  • 42. Lasagna Code There is no problem in computer science that cannot be solved by adding another layer of indirection, except having too many layers of indirection
  • 43. Bad test smells: 4 - Complicated Tests
  • 44. Bad test smells: 4 - Complicated Tests We have a problem, 
 Our code is too difficult to test
  • 45. Bad test smells: 4 - Complicated Tests We have a problem, 
 Our code is too difficult to test Let's write a framework to test it!
  • 46. Bad test smells: 4 - Complicated Tests We have a problem, 
 Our code is too difficult to test Let's write a framework to test it! Ok, now we have 2 problems...
  • 47. Bad test smells: 4 - Complicated Tests We have a problem, 
 Our code is too difficult to test Let's write a framework to test it! Ok, now we have 2 problems... Dedicated test stub must be simple and transparent.
 They should explain the model, not hide it.
  • 48. Bad test smells: 4 - Complicated Tests We have a problem, 
 Our code is too difficult to test Let's write a framework to test it! Ok, now we have 2 problems... Same problem for who has to develop against a big framework: even if I have the framework tests, how can I be sure of not losing pieces around? Let's model domain simply as whole and then split it up for the framework. Dedicated test stub must be simple and transparent.
 They should explain the model, not hide it.
  • 49. Testing Layers separately @Test
 public void retrieveModules() throws Exception {
 Page page = new Page();
 Repository repo = mock(Repository.class);
 UserData context = new UserData("gb");
 
 //first let's get the page layout for the user country in a parsed xml
 MapOfString pageDescriptor = repo.getPageDescriptor(context.getCountry()); 
 //then get the id of actual modules needed matching user context with page layout
 List<String> moduleIds = page.selectModules(context, pageDescriptor);
 
 //get the modules as string properties from parsed xml
 List<MapOfString> modules = repo.getModules(moduleIds);
 
 //to be safe we need to make sure we are using same stub in this test and the next
 assertEquals(STUB_MODULES, modules);
 }
 @Test
 public void composePage() throws Exception {
 //here we continue the flow from the previous test
 Page page = new Page();
 
 //get the modules as string properties from parsed xml
 List<MapOfString> modules = STUB_MODULES;
 
 //compose json page from properties
 String jsonPage = page.compose(modules);
 
 assertEquals(expectedJson, jsonPage);
 }

  • 50. Testing Layers together @Test
 public void composePage() throws Exception {
 //we can use a single test here from xml to json
 
 //only mock Repository, because implementation is in another sub-project
 Repository repo = mock(Repository.class);
 when(repo.getLayoutPage(COUNTRY)).thenReturn(LAYOUT_XML);
 when(repo.getModules(MODULE_IDS)).thenReturn(MODULES_XML);
 
 UserData context = new UserData(COUNTRY);
 
 //instead of MapOfStrings we use a proper object to keep layout
 Layout page = Layout.buildFromXml(repo.getLayoutPage(context.getCountry()));
 
 //we use Module object to keep module properties and methods
 List<Module> moduleList = page.prepareModules(repo, context);
 
 //render the list of modules, easier than with strings properties
 String jsonPage = renderer.toJson(moduleList);
 
 //checking matcher
 assertThat(EXPECTED_JSON, sameJson(jsonPage));
 }
  • 52. How to improve If your tests give you pain don't ignore it. Localise the cause.
  • 53. How to improve If your tests give you pain don't ignore it. Localise the cause.
  • 54. How to improve If your tests give you pain don't ignore it. Localise the cause. Ask to new team members or dev from other teams their impressions.
  • 55. How to improve If your tests give you pain don't ignore it. Localise the cause. Ask to new team members or dev from other teams their impressions.
  • 56. How to improve If your tests give you pain don't ignore it. Localise the cause. Ask to new team members or dev from other teams their impressions. Experiment and share.
  • 57. How to improve If your tests give you pain don't ignore it. Localise the cause. Ask to new team members or dev from other teams their impressions. Experiment and share.
  • 58. How to improve If your tests give you pain don't ignore it. Localise the cause. Ask to new team members or dev from other teams their impressions. Experiment and share. Rule 0: TDD is supposed to be fun and simple.