SlideShare a Scribd company logo
1 of 51
Download to read offline
Test-Driven Development
(that’s not what we meant)
Steve Freeman

steve.freeman@higherorderlogic.com
steve.freeman@higherorderlogic.com ©2015
© http://www.flickr.com/people/29278394@N00/
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
- Write new code only if an
automated test has failed
- Eliminate duplication
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
public class ExchangeRateUploaderTest extends EasyMockTestCase {
private Logger logger;
private CurrencyManager mockCurrencyManager;
private ExchangeRateManager mockExchangeRateManager;
private PriceManagerFactory mockPriceManagerFactory;
private PriceManager mockPriceManager;
private GodObject mockGod;
private DatabaseFacade mockPersistenceManager;
private DatabaseFacade mockFrameworkPersistenceManager;
private CyclicProcessManager mockCyclicProcessManager;
private SystemVariableManager mockSystemVariableManager;
private ScreenManager mockScreenManager;
private Registry registry;
private User adminUser;
private Server server;
private ExchangeRateUploader newExchangeRateUploader(CyclicProcessThread thread) {
return new ExchangeRateUploader(thread) {
@Override protected void initializeAction() throws FrameworkException {
// Does nothing to prevent excessive mocking
}
@Override public Logger getLogger() { return logger; }
@Override protected void setLogMDC() { }
@Override protected User getUser() { return adminUser; }
@Override protected CurrencyManager newCurrencyManager() { return mockCurrencyManager; }
@Override protected PriceManagerFactory newPriceManagerFactory() { return mockPriceManagerFactory; }
@Override protected CyclicProcessManager newCyclicProcessManager() { return mockCyclicProcessManager; }
@Override protected DatabaseFacade newPersistenceManager() { return mockPersistenceManager; }
@Override protected Registry newTaskPerformanceRegistry() { return registry; }
@Override public PriceDataManager getPriceDataManager() { return null; }
@Override protected ExchangeRateManager newExchangeRateManager() { return mockExchangeRateManager; }
};
}
steve.freeman@higherorderlogic.com ©2015
public void testInternalAction() throws FrameworkException {
mockGod = addMock(GodObject.class);
expect(mockGod.getPriceDataManager()).andStubReturn(null);
mockPersistenceManager = addMock(DatabaseFacade.class);
registry = addMock(Registry.class);
adminUser = new TestUser("Admin", "", "", new TestCompany("company"), "");
mockCyclicProcessManager();
registry.finalizeThisThread(isA(String.class), isA(String.class));
Date now = DateUtils.trimMinutesAndSecondsFromDate(new Date());
mockSystemVariableManager();
mockLogger();
mockContextPersistenceManager();
mockPriceManager();
CyclicProcessThread thread = mockUserStateAndGetCyclicProcessThread();
String primeName = "prime";
String aName = "a";
String otherName = "other";
Currency primeCurrency = new TestCurrency(primeName, true);
Currency aCurrency = new TestCurrency(aName, true);
Currency otherCurrency = new TestCurrency(otherName, false);
FXCurrencyPair aCurrencyPair = new FXCurrencyPair(primeCurrency, aCurrency);
FXCurrencyPair otherCurrencyPair = new FXCurrencyPair(otherCurrency, primeCurrency);
setupCurrencyManager(primeCurrency, aCurrency, otherCurrency);
mockExchangeRateManager = addMock(ExchangeRateManager.class);
mockGetFXRatesAtDatesForCurrencies(now, aCurrencyPair, otherCurrencyPair);
FrameworkNumber aCurrencyValue = new FrameworkNumber("5");
FrameworkNumber otherCurrencyValue = new FrameworkNumber("2");
ExchangeRate aCurrencyRate = new ExchangeRate(primeCurrency, aCurrency, aCurrencyValue, now);
ExchangeRate otherCurrencyRate = new ExchangeRate(otherCurrency, primeCurrency, otherCurrencyValue, now);
expect(mockCurrencyManager.getParentToFractionalCurrencyMapForFractionalCurrency()).andStubReturn(newMap());
expect(
mockExchangeRateManager.saveExchangeRate(null, new FrameworkString(primeName), new FrameworkString(aName), aCurrencyValue,
new FrameworkDate(now))).andReturn(null);
expect(
mockExchangeRateManager.saveExchangeRate(null, new FrameworkString(otherName), new FrameworkString(primeName),
otherCurrencyValue, new FrameworkDate(now))).andReturn(null);
Map<String, ExchangeRate> out = new HashMap<String, ExchangeRate>();
out.put("primea", aCurrencyRate);
out.put("otherprime", otherCurrencyRate);
expect(mockPriceManager.getLatestExchangeRates(newList(aCurrencyPair, otherCurrencyPair))).andReturn(out);
mockPMFactoryCleanup();
replayMocks();
ExchangeRateUploader uploader = newExchangeRateUploader(thread);
uploader.initialise();
uploader.run();
}
steve.freeman@higherorderlogic.com ©2015
private void mockPMFactoryCleanup() {
PersistenceFactory mockPersistenceFactory = addMock(PersistenceFactory.class);
mockPersistenceFactory.purgeAllStateForThisThread();
expect(mockGod.getPersistenceFactory()).andReturn(mockPersistenceFactory).anyTimes();
expect(mockPersistenceFactory.getExceptionsInRequest()).andReturn(Collections.<Throwable>emptyList()).times(1);
}
private void mockCyclicProcessManager() throws CyclicProcessException {
mockCyclicProcessManager = addMock(CyclicProcessManager.class);
expect(mockGod.getCyclicProcessManager()).andStubReturn(mockCyclicProcessManager);
mockCyclicProcessManager.updateServerCyclicProcessCurrentRunStatus(isA(String.class),
isA(LISTENER_STATUS.class), isA(String.class), isA(Double.class), isA(Date.class));
expectLastCall().anyTimes();
server = addMock(Server.class);
expect(mockCyclicProcessManager.getThisServer()).andStubReturn(server);
}
private void setupCurrencyManager(Currency primeCurrency, Currency aCurrency, Currency otherCurrency) {
mockCurrencyManager = addMock(CurrencyManager.class);
List<Currency> allCurrencies = new ArrayList<Currency>();
allCurrencies.add(aCurrency);
allCurrencies.add(primeCurrency);
allCurrencies.add(otherCurrency);
expect(mockCurrencyManager.getPrimeCurrency()).andReturn(primeCurrency).anyTimes();
expect(mockCurrencyManager.getAllParentCurrencies()).andReturn(allCurrencies).times(2);
}
private void mockGetFXRatesAtDatesForCurrencies(Date now, FXCurrencyPair aCurrencyPair,
FXCurrencyPair otherCurrencyPair) throws CurrencyException
{
FrameworkNumber originalACurrencyRate = new FrameworkNumber("1.23");
Map<FXCurrencyPair, Collection<Date>> currencyPairAndDatesMap = new HashMap<FXCurrencyPair, Collection<Date>>();
currencyPairAndDatesMap.put(aCurrencyPair, Arrays.asList(now));
currencyPairAndDatesMap.put(otherCurrencyPair, Arrays.asList(now));
FXCurrencyPairRates outputObj = addMock(FXCurrencyPairRates.class);
expect(outputObj.rateMapSize()).andReturn(5).anyTimes();
expect(outputObj.getActualPriceDateForCurrencyPair(aCurrencyPair, now)).andReturn(null).once();
expect(outputObj.getRateFromFxRateMap(now, aCurrencyPair)).andReturn(originalACurrencyRate).once();
expect(outputObj.getActualPriceDateForCurrencyPair(otherCurrencyPair, now)).andReturn(null).once();
expect(outputObj.getRateFromFxRateMap(now, otherCurrencyPair)).andReturn(originalACurrencyRate);
expect(mockExchangeRateManager.getFXRatesAtDatesForCurrencies(currencyPairAndDatesMap)).andReturn(outputObj);
}
steve.freeman@higherorderlogic.com ©2015
private CyclicProcessThread mockUserStateAndGetCyclicProcessThread() {
Role mockAdminRole = addMock(Role.class);
CyclicProcessThread thread = addMock(CyclicProcessThread.class);
expect(thread.getAdminRole()).andReturn(mockAdminRole).anyTimes();
expect(thread.getAdminUser()).andReturn(adminUser).anyTimes();
thread.interrupt();
expectLastCall();
mockScreenManager = addMock(ScreenManager.class);
expect(mockGod.getScreenManager()).andReturn(mockScreenManager).anyTimes();
mockScreenManager.setThreadSignedOnState(new SignedOnState(adminUser, mockAdminRole, false));
expectLastCall().anyTimes();
expect(thread.getGod()).andReturn(mockGod).anyTimes();
expect(thread.getShutdownInProgress()).andReturn(false).anyTimes();
return thread;
}
private void mockContextPersistenceManager() {
mockFrameworkPersistenceManager = addMock(DatabaseFacade.class);
expect(mockGod.getDatabaseFacade()).andReturn(mockFrameworkPersistenceManager).anyTimes();
mockFrameworkPersistenceManager.beginNewSession();
expectLastCall().anyTimes();
}
private void mockPriceManager() throws PriceException {
mockPriceManagerFactory = addMock(PriceManagerFactory.class);
mockPriceManager = addMock(PriceManager.class);
expect(mockPriceManagerFactory.newPriceManager(mockFrameworkPersistenceManager,
mockSystemVariableManager, null))
.andReturn(mockPriceManager).once();
}
private void mockSystemVariableManager() {
mockSystemVariableManager = addMock(SystemVariableManager.class);
expect(mockGod.getSystemVariableManager()).andReturn(mockSystemVariableManager).anyTimes();
expect(mockSystemVariableManager.getSystemVariable(CYCLIC_PROCESS_LISTENER_HEART_BEAT_TOLERANCE, "30000"))
.andReturn("30000").anyTimes();
}
private void mockLogger() {
logger = addMock(Logger.class);
logger.info(isA(String.class)); expectLastCall().atLeastOnce();
logger.debug(isA(String.class)); expectLastCall().atLeastOnce();
}
}
steve.freeman@higherorderlogic.com ©2015
Keith Braithwaite
steve.freeman@higherorderlogic.com ©2015
Difficult to understand
Overspecified
Obscure
Brittle
Meaningless failures
steve.freeman@higherorderlogic.com ©2015
“Security Theatre”
steve.freeman@higherorderlogic.com ©2015
Test-Driven Theatre
steve.freeman@higherorderlogic.com ©2015
Should!
steve.freeman@higherorderlogic.com ©2015
given_I_have_a_Foo_when_I_call_setBar_with_3_then_getBar_should_return_3()
steve.freeman@higherorderlogic.com ©2015
What are the tests for TDD?
steve.freeman@higherorderlogic.com ©2015
Steady, incremental progress
steve.freeman@higherorderlogic.com ©2015
Constant positive reinforcement
steve.freeman@higherorderlogic.com ©2015
I think before I code
steve.freeman@higherorderlogic.com ©2015
Things break when they’re
supposed to
steve.freeman@higherorderlogic.com ©2015
Surprising designs emerge
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
BasketTest.add_adding_item()

sut = new Basket()

sut.add(ITEM)

assertEquals(

ITEM,

backdoor(sut, “itemList”)[0])
steve.freeman@higherorderlogic.com ©2015
Write readable code
steve.freeman@higherorderlogic.com ©2015
is_empty_when_created()

assertThat( new Basket().itemCount(), 

equals(0) )
returns_items_in_the_order_they_were_added()

basket = new Basket()

.add(pen).add(ink).add(paper)

assertThat( basket, 

hasItems(pen, ink, paper) )
totals_up_the_cost_of_its_items()
fails_when_removing_an_absent_item()

...
steve.freeman@higherorderlogic.com ©2015
is_empty_when_created
assertThat( new Basket().itemCount(), 

equals(0) )
returns_items_in_the_order_they_were_added
.add(
assertThat(
hasItems(
totals_up_the_cost_of_its_items
fails_when_removing_an_absent_item
...
Interfaces,
not internals
steve.freeman@higherorderlogic.com ©2015
is_empty_when_created
assertThat( new Basket().itemCount(), 

equals(0) )
returns_items_in_the_order_they_were_added
.add(
assertThat(
hasItems(
totals_up_the_cost_of_its_items
fails_when_removing_an_absent_item
...
Protocols,
not Interfaces
steve.freeman@higherorderlogic.com ©2015
is_empty_when_created
assertThat( new Basket().itemCount(), 

equals(0) )
returns_items_in_the_order_they_were_added
.add(
assertThat(
hasItems(
totals_up_the_cost_of_its_items
fails_when_removing_an_absent_item
...
From simple

to general
steve.freeman@higherorderlogic.com ©2015
“It’s about explaining the domain, 

not about proving the 

correctness of the code.”
Andrew Parker
steve.freeman@higherorderlogic.com ©2015
When you’re lost, slow down
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
Test at the right level
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
© outbrain.com (not an endorsement)
steve.freeman@higherorderlogic.com ©2015
Why does TDD work?
steve.freeman@higherorderlogic.com ©2015
Focussed
steve.freeman@higherorderlogic.com ©2015
i thought, what a stupid idea. i want tests that pass, not
tests that fail. why would i write a test when i was sure it
would fail. well, i'm in the habit of trying stupid things out
just to see what happens, so i tried it and it worked great.
i was finally able to separate logical from physical
design. i'd always been told to do that but no one
ever explained how.
it said the way to program is to look at the input tape
and manually type in the output tape you expect. then
you program until the actual and expected tapes match.
steve.freeman@higherorderlogic.com ©2015
Concrete
steve.freeman@higherorderlogic.com ©2015(cc) flickr users

zoenet, 22850192@N03, dalbera, free-stock, jonhurd, mccaffry, waytru, zigazou76
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
Empirical
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
steve.freeman@higherorderlogic.com ©2015
Test-Driven Development
(that’s not what we meant)
steve.freeman@higherorderlogic.com

More Related Content

Similar to Tdd thats-not-what-we-meant

생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트기룡 남
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Jason Lotito
 
MySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web ApplicationsMySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web ApplicationsOSSCube
 
JSR 354 Hackday - What you can do...
JSR 354 Hackday - What you can do...JSR 354 Hackday - What you can do...
JSR 354 Hackday - What you can do...Anatole Tresch
 
The Ring programming language version 1.9 book - Part 93 of 210
The Ring programming language version 1.9 book - Part 93 of 210The Ring programming language version 1.9 book - Part 93 of 210
The Ring programming language version 1.9 book - Part 93 of 210Mahmoud Samir Fayed
 
Testing with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifeTesting with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifePeter Gfader
 
Spring MVC Intro / Gore - Nov NHJUG
Spring MVC Intro / Gore - Nov NHJUGSpring MVC Intro / Gore - Nov NHJUG
Spring MVC Intro / Gore - Nov NHJUGTed Pennings
 
Java Unit Test and Coverage Introduction
Java Unit Test and Coverage IntroductionJava Unit Test and Coverage Introduction
Java Unit Test and Coverage IntroductionAlex Su
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutionsbenewu
 
Asynchronous JavaScript Programming
Asynchronous JavaScript ProgrammingAsynchronous JavaScript Programming
Asynchronous JavaScript ProgrammingHaim Michael
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Patterngoodfriday
 
淺談高效撰寫單元測試
淺談高效撰寫單元測試淺談高效撰寫單元測試
淺談高效撰寫單元測試Zen K.C
 
GDSC NCU Flutter
GDSC NCU FlutterGDSC NCU Flutter
GDSC NCU FlutterNCUDSC
 
.NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012).NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012)David McCarter
 
Vaadin 7 Today and Tomorrow
Vaadin 7 Today and TomorrowVaadin 7 Today and Tomorrow
Vaadin 7 Today and TomorrowJoonas Lehtinen
 

Similar to Tdd thats-not-what-we-meant (20)

생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트생산적인 개발을 위한 지속적인 테스트
생산적인 개발을 위한 지속적인 테스트
 
Designing for Autonomy
Designing for AutonomyDesigning for Autonomy
Designing for Autonomy
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Test driven development
Test driven developmentTest driven development
Test driven development
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
 
MySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web ApplicationsMySQL Stored Procedures: Building High Performance Web Applications
MySQL Stored Procedures: Building High Performance Web Applications
 
JSR 354 Hackday - What you can do...
JSR 354 Hackday - What you can do...JSR 354 Hackday - What you can do...
JSR 354 Hackday - What you can do...
 
The Ring programming language version 1.9 book - Part 93 of 210
The Ring programming language version 1.9 book - Part 93 of 210The Ring programming language version 1.9 book - Part 93 of 210
The Ring programming language version 1.9 book - Part 93 of 210
 
Java Se next Generetion
Java Se next GeneretionJava Se next Generetion
Java Se next Generetion
 
Testing with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs LifeTesting with VS2010 - A Bugs Life
Testing with VS2010 - A Bugs Life
 
Spring MVC Intro / Gore - Nov NHJUG
Spring MVC Intro / Gore - Nov NHJUGSpring MVC Intro / Gore - Nov NHJUG
Spring MVC Intro / Gore - Nov NHJUG
 
Java Unit Test and Coverage Introduction
Java Unit Test and Coverage IntroductionJava Unit Test and Coverage Introduction
Java Unit Test and Coverage Introduction
 
Unit test candidate solutions
Unit test candidate solutionsUnit test candidate solutions
Unit test candidate solutions
 
Asynchronous JavaScript Programming
Asynchronous JavaScript ProgrammingAsynchronous JavaScript Programming
Asynchronous JavaScript Programming
 
Developing ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller PatternDeveloping ASP.NET Applications Using the Model View Controller Pattern
Developing ASP.NET Applications Using the Model View Controller Pattern
 
淺談高效撰寫單元測試
淺談高效撰寫單元測試淺談高效撰寫單元測試
淺談高效撰寫單元測試
 
Adopt JSR 354
Adopt JSR 354Adopt JSR 354
Adopt JSR 354
 
GDSC NCU Flutter
GDSC NCU FlutterGDSC NCU Flutter
GDSC NCU Flutter
 
.NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012).NET Coding Standards For The Real World (2012)
.NET Coding Standards For The Real World (2012)
 
Vaadin 7 Today and Tomorrow
Vaadin 7 Today and TomorrowVaadin 7 Today and Tomorrow
Vaadin 7 Today and Tomorrow
 

More from AHAConference

代码的用户体验
代码的用户体验代码的用户体验
代码的用户体验AHAConference
 
白日梦飞行地图
白日梦飞行地图白日梦飞行地图
白日梦飞行地图AHAConference
 
What is business model
What is business modelWhat is business model
What is business modelAHAConference
 
What is business model
What is business modelWhat is business model
What is business modelAHAConference
 
精益产品开发实例
精益产品开发实例精益产品开发实例
精益产品开发实例AHAConference
 
一个互联网产品的成长史
一个互联网产品的成长史一个互联网产品的成长史
一个互联网产品的成长史AHAConference
 
Agile organization design workshop
Agile organization design workshopAgile organization design workshop
Agile organization design workshopAHAConference
 
What is business model
What is business modelWhat is business model
What is business modelAHAConference
 
互联网产品演进中的组织适应
互联网产品演进中的组织适应互联网产品演进中的组织适应
互联网产品演进中的组织适应AHAConference
 
Odde conference effectiveteamv5-sc-1
Odde conference effectiveteamv5-sc-1Odde conference effectiveteamv5-sc-1
Odde conference effectiveteamv5-sc-1AHAConference
 

More from AHAConference (13)

翻转组织
翻转组织翻转组织
翻转组织
 
代码的用户体验
代码的用户体验代码的用户体验
代码的用户体验
 
白日梦飞行地图
白日梦飞行地图白日梦飞行地图
白日梦飞行地图
 
What is business model
What is business modelWhat is business model
What is business model
 
What is business model
What is business modelWhat is business model
What is business model
 
精益产品开发实例
精益产品开发实例精益产品开发实例
精益产品开发实例
 
一个互联网产品的成长史
一个互联网产品的成长史一个互联网产品的成长史
一个互联网产品的成长史
 
Agile organization design workshop
Agile organization design workshopAgile organization design workshop
Agile organization design workshop
 
What is business model
What is business modelWhat is business model
What is business model
 
Mc aha-20150416
Mc aha-20150416Mc aha-20150416
Mc aha-20150416
 
互联网产品演进中的组织适应
互联网产品演进中的组织适应互联网产品演进中的组织适应
互联网产品演进中的组织适应
 
Nmonecis aha
Nmonecis   ahaNmonecis   aha
Nmonecis aha
 
Odde conference effectiveteamv5-sc-1
Odde conference effectiveteamv5-sc-1Odde conference effectiveteamv5-sc-1
Odde conference effectiveteamv5-sc-1
 

Tdd thats-not-what-we-meant