2010.10.30 steven sustaining tdd   agile tour shenzhen
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

2010.10.30 steven sustaining tdd agile tour shenzhen

on

  • 723 views

 

Statistics

Views

Total Views
723
Views on SlideShare
723
Embed Views
0

Actions

Likes
0
Downloads
6
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

2010.10.30 steven sustaining tdd agile tour shenzhen Presentation Transcript

  • 1. www.odd-e.com | steven@odd-e.com Sustainable Test Driven DevelopmentThursday, 4 November 2010
  • 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 2Thursday, 4 November 2010
  • 3. Agenda • Test-Driven Development in 1 slide • Readability • Modifying tons of tests whenever we change code?! 3Thursday, 4 November 2010
  • 4. Test Driven Development 4Thursday, 4 November 2010
  • 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”) 5Thursday, 4 November 2010
  • 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) Iteration start Iteration end Integrate Integrate Integrate 6Thursday, 4 November 2010
  • 7. Never Skip Refactoring 7Thursday, 4 November 2010
  • 8. Naming 8Thursday, 4 November 2010
  • 9. Have you seen tests like this? TEST (TEST_AIH, TEST1) TEST (TEST_AIH, TEST2) TEST (TEST_AIH, TEST3) TEST (TEST_AIH, TEST4) 9Thursday, 4 November 2010
  • 10. Whatʼs wrong? TEST (TEST_AIH, FAIL_BAD_PARAM) 10Thursday, 4 November 2010
  • 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 11Thursday, 4 November 2010
  • 12. TestDox convention public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […] What it does? Credit: Growing OO Software, Guided by Tests 12Thursday, 4 November 2010
  • 13. TestDox convention public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […] Pre-condition / Input Credit: Growing OO Software, Guided by Tests 13Thursday, 4 November 2010
  • 14. Structuring it well 14Thursday, 4 November 2010
  • 15. Test file organisation • Keep Test Logic Out of Production Code • Same logical package but physically store them in a parallel source tree 15Thursday, 4 November 2010
  • 16. Test case classes • Test case class per class? • Test case class per feature? • Test case class per fixture? 16Thursday, 4 November 2010
  • 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 17Thursday, 4 November 2010
  • 18. Example Setting up TEST(LightScheduler, ScheduleWeekEndItsSaturday) { LightScheduler_ScheduleTurnOn(3, WEEKEND, 100); FakeTimeService_SetDay(SATURDAY); FakeTimeService_SetMinute(100); LightScheduler_Wakeup(); Exercise LONGS_EQUAL(3, FakeLightController_getLastId()); LONGS_EQUAL(LIGHT_ON, FakeLightController_getLastState()); } Verify Credit: Test Driven Development for Embedded C 18Thursday, 4 November 2010
  • 19. BDD Style • Given some precondition • When something happens • Then something that is dependent on Given and When should be true 19Thursday, 4 November 2010
  • 20. Example TEST(LightScheduler, ScheduleOffWeekendAndItsSaturdayAndItsTime) { LightScheduler_ScheduleTurnOff(lightNumber, WEEKEND, scheduledMinute); whenItBecomes(SATURDAY, scheduledMinute); thenExpect(lightNumber, LIGHT_OFF); } Credit: Test Driven Development for Embedded C 20Thursday, 4 November 2010
  • 21. Question: I have a lot to setup 21Thursday, 4 November 2010
  • 22. Have your tried fixture? TEST_GROUP (TEST_thisObject) { void setup() { } void teardown() { } }; 22Thursday, 4 November 2010
  • 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); } Credit: Test Driven - Practical TDD and Acceptance TDD for Java Developers 23Thursday, 4 November 2010
  • 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)); } } Credit: Test Driven - Practical TDD and Acceptance TDD for Java Developers 24Thursday, 4 November 2010
  • 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)); […] } 25Thursday, 4 November 2010
  • 26. Test Data Builder new OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode().build()) .build()) .build(); 26Thursday, 4 November 2010
  • 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. 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))); http://code.google.com/p/make-it-easy/ 28Thursday, 4 November 2010
  • 29. Try: One assertion per test 29Thursday, 4 November 2010
  • 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); } } 30Thursday, 4 November 2010
  • 31. At least: One concept per test 31Thursday, 4 November 2010
  • 32. Hamcrest • Framework for writing declarative match criteria 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)); Or even better assertThat(s, containsString("bananas")); assertThat(s, not(containsString("mangoes")); http://code.google.com/p/hamcrest/ 32Thursday, 4 November 2010
  • 33. Meaningful Assertion Messages • 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 33Thursday, 4 November 2010
  • 34. Describe what happened assertTrue(“Expected a > b but a was ‘“ + a.toString() + “‘ and b was ‘“ + b.toString() + “‘“, a > b); Credit: The Art of Unit Testing 34Thursday, 4 November 2010
  • 35. Brittle Tests 35Thursday, 4 November 2010
  • 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!” ... 36Thursday, 4 November 2010
  • 37. Test/Code Duplication • 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 37Thursday, 4 November 2010
  • 38. Donʼt forget higher level testing • Tests pass with test doubles... but might still fail at production due to unexpected / untested interactions 38Thursday, 4 November 2010
  • 39. Mock Overload • Excessive use of mocks and expectations - perhaps a design issue, are you following SRP? 39Thursday, 4 November 2010
  • 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 FRIENDS 40Thursday, 4 November 2010
  • 41. Indirection • Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled 41Thursday, 4 November 2010
  • 42. Not testable? • Do you follow good design principles? 42Thursday, 4 November 2010
  • 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 43Thursday, 4 November 2010
  • 44. Doing it better is not harder. Itʼs easier - do it better! Thank you! 44Thursday, 4 November 2010