Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
www.odd-e.com | steven@odd-e.com
Sustainable
Test Driven Development
Thursday, 4 November 2010
Who am I?
•Name: Steven Mak
•Agile Coach at Odd-e
•Lives in Hong Kong
•Agile, TDD Coaching
•I love coding - Java, C/C++,
P...
Agenda
•Test-Driven Development in 1 slide
•Readability
•Modifying tons of tests whenever we change code?!
3
Thursday, 4 N...
Test Driven Development
4
Thursday, 4 November 2010
Test driven development
•1 Rule:
-Only ever write code to fix a failing test
•3 Steps:
1. Write a test (which fails “red”)
...
Role of TDD in iterative
development
• Iteration cycle: 2-4 weeks
• Daily build: Every day (of course)
• Continuous integr...
Never Skip Refactoring
7
Thursday, 4 November 2010
Naming
8
Thursday, 4 November 2010
Have you seen tests like this?
TEST (TEST_AIH, TEST1)
TEST (TEST_AIH, TEST2)
TEST (TEST_AIH, TEST3)
TEST (TEST_AIH, TEST4)...
Whatʼs wrong?
TEST (TEST_AIH, FAIL_BAD_PARAM)
10
Thursday, 4 November 2010
What names tell us?
• Who
- Name of the SUT class
- Name of the method or feature being exercised
• Input
- Important char...
TestDox convention
public class ListTests {
@Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […]
12
C...
TestDox convention
public class ListTests {
@Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […]
13
C...
Structuring it well
14
Thursday, 4 November 2010
Test file organisation
•Keep Test Logic Out of Production Code
•Same logical package but physically store them
in a paralle...
Test case classes
•Test case class per class?
•Test case class per feature?
•Test case class per fixture?
16
Thursday, 4 No...
Four-Phase Test Pattern
•Setup - establish the preconditions to the test
•Exercise - Do something to the system
•Verify - ...
Example
TEST(LightScheduler, ScheduleWeekEndItsSaturday)
{
LightScheduler_ScheduleTurnOn(3, WEEKEND, 100);
FakeTimeService...
BDD Style
•Given some precondition
•When something happens
•Then something that is dependent on Given
and When should be t...
Example
TEST(LightScheduler, ScheduleOffWeekendAndItsSaturdayAndItsTime)
{
LightScheduler_ScheduleTurnOff(lightNumber, WEE...
Question: I have a lot to setup
21
Thursday, 4 November 2010
Have your tried fixture?
TEST_GROUP (TEST_thisObject)
{

 void setup()

 {

 }

 void teardown()

 {

 }
};
22
Thursday, 4 ...
Complex Data Creation
@Before
public void setUp() throws Exception {

 alice = new Person();

 alice.setId(1L);

 alice.se...
Parameterised Creation
public class ParameterizedCreationMethodExample {

 private Person alice, billy, clark;

 @Before

...
More complex data creation
@Test public void chargesCustomerForTotalCostOfAllOrderedItems() {

 Order order = new Order(

...
Test Data Builder
new OrderBuilder()

 .fromCustomer(

 
 new CustomerBuilder()

 
 
 .withAddress(new AddressBuilder().wi...
Test Data Builder
public class OrderBuilder {

 private Customer customer = new CustomerBuilder().build();

 private List<...
make-it-easy
28
http://code.google.com/p/make-it-easy/
Maker<Apple> appleWith2Leaves = an(Apple, with(2, leaves));
Maker<A...
Try: One assertion per test
29
Thursday, 4 November 2010
Customised Assertions
#define CHECK_OBJ(a,b) CHECK_OBJ(a,b, __FILE__,__FILE__)
void CHECK_OBJ(struct* yourObj, struct* myO...
At least: One concept per test
31
Thursday, 4 November 2010
Hamcrest
• Framework for writing declarative match criteria
32http://code.google.com/p/hamcrest/
String s = "yes we have n...
Meaningful Assertion Messages
33
•Donʼt repeat what the built-in test framework
outputs to the console (e.g. name of the t...
Describe what happened
assertTrue(“Expected a > b but a was ‘“ +

 a.toString() +

 “‘ and b was ‘“ +

 b.toString() + “‘“...
Brittle Tests
35
Thursday, 4 November 2010
DRY
Letʼs repeat saying:
“Donʼt Repeat Yourself!”
“Donʼt Repeat Yourself!”
“Donʼt Repeat Yourself!”
“Donʼt Repeat Yourself...
Test/Code Duplication
37
• Too many expectations or too specific expectations lead to tests that fail
due to the slightest ...
Donʼt forget higher level testing
• Tests pass with test doubles... but might still fail at production due to
unexpected /...
Mock Overload
• Excessive use of mocks and expectations
- perhaps a design issue, are you following SRP?
39
Thursday, 4 No...
Principles
• Donʼt mock code you donʼt own - create your own interface to wrap the
interaction with the external API
• Onl...
Indirection
41
• Assign the responsibility to an intermediate object to mediate between
other components or services so th...
Not testable?
42
•Do you follow good design principles?
Thursday, 4 November 2010
References
• Practical TDD and ATDD for Java Developers - Lasse Koskela
• Practices for scaling Agile and Lean practices -...
44
Doing it better is not harder.
Itʼs easier - do it better!
Thank you!
Thursday, 4 November 2010
Upcoming SlideShare
Loading in …5
×

Sustainable TDD

1,323 views

Published on

Published in: Technology
  • Be the first to comment

Sustainable TDD

  1. 1. www.odd-e.com | steven@odd-e.com Sustainable Test Driven Development Thursday, 4 November 2010
  2. 2. Who am I? •Name: Steven Mak •Agile Coach at Odd-e •Lives in Hong Kong •Agile, TDD Coaching •I love coding - Java, C/C++, PHP, Perl, C#, VB and some weird languages •I can speak Mandarin, Cantonese, and English 2 Thursday, 4 November 2010
  3. 3. Agenda •Test-Driven Development in 1 slide •Readability •Modifying tons of tests whenever we change code?! 3 Thursday, 4 November 2010
  4. 4. Test Driven Development 4 Thursday, 4 November 2010
  5. 5. Test driven development •1 Rule: -Only ever write code to fix a failing test •3 Steps: 1. Write a test (which fails “red”) 2. Code (to make test pass “green”) 3. Refactor (test still passes “green”) 5 Thursday, 4 November 2010
  6. 6. Role of TDD in iterative development • Iteration cycle: 2-4 weeks • Daily build: Every day (of course) • Continuous integration cycle: multiple times a day (preferably every 10 minutes) • TDD Cycle: A few minutes (usually 3 - 15 min per cycle) Integrate Integrate Integrate Iterationstart Iterationend 6 Thursday, 4 November 2010
  7. 7. Never Skip Refactoring 7 Thursday, 4 November 2010
  8. 8. Naming 8 Thursday, 4 November 2010
  9. 9. Have you seen tests like this? TEST (TEST_AIH, TEST1) TEST (TEST_AIH, TEST2) TEST (TEST_AIH, TEST3) TEST (TEST_AIH, TEST4) 9 Thursday, 4 November 2010
  10. 10. Whatʼs wrong? TEST (TEST_AIH, FAIL_BAD_PARAM) 10 Thursday, 4 November 2010
  11. 11. What names tell us? • Who - Name of the SUT class - Name of the method or feature being exercised • Input - Important characteristics of any input values - Anything relevant about the state • Output - The outputs expected - The expected post-exercise state 11 Thursday, 4 November 2010
  12. 12. TestDox convention public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […] 12 Credit: Growing OO Software, Guided by Tests What it does? Thursday, 4 November 2010
  13. 13. TestDox convention public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […] 13 Credit: Growing OO Software, Guided by Tests Pre-condition / Input Thursday, 4 November 2010
  14. 14. Structuring it well 14 Thursday, 4 November 2010
  15. 15. Test file organisation •Keep Test Logic Out of Production Code •Same logical package but physically store them in a parallel source tree 15 Thursday, 4 November 2010
  16. 16. Test case classes •Test case class per class? •Test case class per feature? •Test case class per fixture? 16 Thursday, 4 November 2010
  17. 17. Four-Phase Test Pattern •Setup - establish the preconditions to the test •Exercise - Do something to the system •Verify - Check the expected outcome •Cleanup - Return the SUT to its initial state after the test 17 Thursday, 4 November 2010
  18. 18. Example TEST(LightScheduler, ScheduleWeekEndItsSaturday) { LightScheduler_ScheduleTurnOn(3, WEEKEND, 100); FakeTimeService_SetDay(SATURDAY); FakeTimeService_SetMinute(100); LightScheduler_Wakeup(); LONGS_EQUAL(3, FakeLightController_getLastId()); LONGS_EQUAL(LIGHT_ON, FakeLightController_getLastState()); } 18 Credit: Test Driven Development for Embedded C Setting up Exercise Verify Thursday, 4 November 2010
  19. 19. BDD Style •Given some precondition •When something happens •Then something that is dependent on Given and When should be true 19 Thursday, 4 November 2010
  20. 20. Example TEST(LightScheduler, ScheduleOffWeekendAndItsSaturdayAndItsTime) { LightScheduler_ScheduleTurnOff(lightNumber, WEEKEND, scheduledMinute); whenItBecomes(SATURDAY, scheduledMinute); thenExpect(lightNumber, LIGHT_OFF); } 20 Credit: Test Driven Development for Embedded C Thursday, 4 November 2010
  21. 21. Question: I have a lot to setup 21 Thursday, 4 November 2010
  22. 22. Have your tried fixture? TEST_GROUP (TEST_thisObject) { void setup() { } void teardown() { } }; 22 Thursday, 4 November 2010
  23. 23. Complex Data Creation @Before public void setUp() throws Exception { alice = new Person(); alice.setId(1L); alice.setFirstname("Alice"); alice.setLastname("Adams"); alice.setSsn("111111"); billy = new Person(); billy.setId(2L); billy.setFirstname("Billy"); billy.setLastname("Burke"); billy.setSsn("222222"); clark = new Person(); clark.setId(3L); clark.setFirstname("Clark"); clark.setLastname("Cable"); clark.setSsn("333333"); alice.isInLoveWith(billy); } 23 Credit: Test Driven - Practical TDD and Acceptance TDD for Java Developers Thursday, 4 November 2010
  24. 24. Parameterised Creation public class ParameterizedCreationMethodExample { private Person alice, billy, clark; @Before public void setUp() throws Exception { clark = createPerson("Clark", "Cable"); billy = createPerson("Billy", "Burke"); alice = createPerson("Alice", "Adams"); alice.isInLoveWith(billy); } private Person createPerson(String firstName, String lastName) { Person person = new Person(); person.setFirstname(firstName); person.setLastname(lastName); person.setId(UniqueNumber.next()); person.setSsn(String.valueOf(UniqueNumber.next())); return person; } @Test public void aliceShouldAcceptWhenProposedToByBilly() throws Exception { billy.proposeTo(alice); assertTrue(alice.isEngagedWith(billy)); } } 24 Credit: Test Driven - Practical TDD and Acceptance TDD for Java Developers Thursday, 4 November 2010
  25. 25. More complex data creation @Test public void chargesCustomerForTotalCostOfAllOrderedItems() { Order order = new Order( new Customer("Sherlock Holmes", new Address("221b Baker Street", "London", new PostCode("NW1", "3RX")))); order.addLine(new OrderLine("Deerstalker Hat", 1)); order.addLine(new OrderLine("Tweed Cape", 1)); […] } 25 Thursday, 4 November 2010
  26. 26. Test Data Builder new OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode().build()) .build()) .build(); 26 Thursday, 4 November 2010
  27. 27. Test Data Builder public class OrderBuilder { private Customer customer = new CustomerBuilder().build(); private List<OrderLine> lines = new ArrayList<OrderLine>(); private BigDecimal discountRate = BigDecimal.ZERO; public static OrderBuilder anOrder() { return new OrderBuilder(); } public OrderBuilder withCustomer(Customer customer) { this.customer = customer; return this; } public OrderBuilder withOrderLines(OrderLines lines) { this.lines = lines; return this; } public OrderBuilder withDiscount(BigDecimal discountRate) { this.discountRate = discountRate; return this; } public Order build() { Order order = new Order(customer); for (OrderLine line : lines) order.addLine(line); order.setDiscountRate(discountRate); } } } 27 Thursday, 4 November 2010
  28. 28. make-it-easy 28 http://code.google.com/p/make-it-easy/ Maker<Apple> appleWith2Leaves = an(Apple, with(2, leaves)); Maker<Apple> ripeApple = appleWith2Leaves.but(with(ripeness, 0.9)); Maker<Apple> unripeApple = appleWith2Leaves.but(with(ripeness, 0.125));         Apple apple1 = make(ripeApple); Apple apple2 = make(unripeApple);         Banana defaultBanana = make(a(Banana)); Banana straightBanana = make(a(Banana, with(curve, 0.0))); Banana squishyBanana = make(a(Banana, with(ripeness, 1.0))); Thursday, 4 November 2010
  29. 29. Try: One assertion per test 29 Thursday, 4 November 2010
  30. 30. Customised Assertions #define CHECK_OBJ(a,b) CHECK_OBJ(a,b, __FILE__,__FILE__) void CHECK_OBJ(struct* yourObj, struct* myObj, const char* file, int line) { if (structs are not equal) { SimpleString errorMessage = StringFromFormat( “My struct: %d, %p, %s”, myObj->d, myObj->p, myObj->s); FAIL_LOCATION(errorMessage.asCharString(), file, line); } } 30 Thursday, 4 November 2010
  31. 31. At least: One concept per test 31 Thursday, 4 November 2010
  32. 32. Hamcrest • Framework for writing declarative match criteria 32http://code.google.com/p/hamcrest/ String s = "yes we have no bananas today"; Matcher<String> containsBananas = new StringContains("bananas"); Matcher<String> containsMangoes = new StringContains("mangoes"); assertTrue(containsBananas.matches(s)); assertFalse(containsMangoes.matches(s)); assertThat(s, containsString("bananas")); assertThat(s, not(containsString("mangoes")); Or even better Thursday, 4 November 2010
  33. 33. Meaningful Assertion Messages 33 •Donʼt repeat what the built-in test framework outputs to the console (e.g. name of the test method) •Donʼt repeat what the test name explains •If you donʼt have anything good to say, you donʼt have to say anything •Write what should have happened, or what failed to happen, and possibly mention when it should have happened Thursday, 4 November 2010
  34. 34. Describe what happened assertTrue(“Expected a > b but a was ‘“ + a.toString() + “‘ and b was ‘“ + b.toString() + “‘“, a > b); 34 Credit: The Art of Unit Testing Thursday, 4 November 2010
  35. 35. Brittle Tests 35 Thursday, 4 November 2010
  36. 36. DRY Letʼs repeat saying: “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” “Donʼt Repeat Yourself!” ... 36 Thursday, 4 November 2010
  37. 37. Test/Code Duplication 37 • Too many expectations or too specific expectations lead to tests that fail due to the slightest of refactorings • Ways to avoid - Keep principles of behaviour verification in when writing expectations - Consider using stubs instead of mocks if the expectations do not help meet the goal of the test Thursday, 4 November 2010
  38. 38. Donʼt forget higher level testing • Tests pass with test doubles... but might still fail at production due to unexpected / untested interactions 38 Thursday, 4 November 2010
  39. 39. Mock Overload • Excessive use of mocks and expectations - perhaps a design issue, are you following SRP? 39 Thursday, 4 November 2010
  40. 40. Principles • Donʼt mock code you donʼt own - create your own interface to wrap the interaction with the external API • Only Mock your nearest neighbour - The law of Demeter 40 FRIENDS Thursday, 4 November 2010
  41. 41. Indirection 41 • Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled Thursday, 4 November 2010
  42. 42. Not testable? 42 •Do you follow good design principles? Thursday, 4 November 2010
  43. 43. References • Practical TDD and ATDD for Java Developers - Lasse Koskela • Practices for scaling Agile and Lean practices - Craig Larman and Bas Vodde • Growing OO Software, guided by tests - Steve Freeman and Nat Pryce • TDD for Embedded C - James Grenning • xUnit Test Patterns - Gerard Meszaros • Working Effectively with Legacy Code - Michael Feathers • Clean Code - Robert Martin 43 Thursday, 4 November 2010
  44. 44. 44 Doing it better is not harder. Itʼs easier - do it better! Thank you! Thursday, 4 November 2010

×