44
www.odd-e.com | [email protected] Sustainable Test Driven Development Thursday, 4 November 2010

2010.10.30 steven sustaining tdd agile tour shenzhen

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: 2010.10.30 steven sustaining tdd   agile tour shenzhen

www.odd-e.com | [email protected]

SustainableTest Driven Development

Thursday, 4 November 2010

Page 2: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 3: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Agenda

•Test-Driven Development in 1 slide•Readability•Modifying tons of tests whenever we change code?!

3

Thursday, 4 November 2010

Page 4: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Test Driven Development

4

Thursday, 4 November 2010

Page 5: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 6: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Iteration start

Iteration end

6

Thursday, 4 November 2010

Page 7: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Never Skip Refactoring

7

Thursday, 4 November 2010

Page 8: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Naming

8

Thursday, 4 November 2010

Page 9: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 10: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Whatʼs wrong?

TEST (TEST_AIH, FAIL_BAD_PARAM)

10

Thursday, 4 November 2010

Page 11: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 12: 2010.10.30 steven sustaining tdd   agile tour shenzhen

TestDox convention

public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […]

12

Credit: Growing OO Software, Guided by Tests

What it does?

Thursday, 4 November 2010

Page 13: 2010.10.30 steven sustaining tdd   agile tour shenzhen

TestDox convention

public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […]

13

Credit: Growing OO Software, Guided by Tests

Pre-condition / Input

Thursday, 4 November 2010

Page 14: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Structuring it well

14

Thursday, 4 November 2010

Page 15: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 16: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Test case classes

•Test case class per class?•Test case class per feature?•Test case class per fixture?

16

Thursday, 4 November 2010

Page 17: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 18: 2010.10.30 steven sustaining tdd   agile tour shenzhen

ExampleTEST(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

Page 19: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 20: 2010.10.30 steven sustaining tdd   agile tour shenzhen

ExampleTEST(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

Page 21: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Question: I have a lot to setup

21

Thursday, 4 November 2010

Page 22: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Have your tried fixture?TEST_GROUP (TEST_thisObject){ void setup() { }

void teardown() { }};

22

Thursday, 4 November 2010

Page 23: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Complex Data Creation@Beforepublic 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

Page 24: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Parameterised Creationpublic 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

Page 25: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 26: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Test Data Buildernew OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode().build()) .build()) .build();

26

Thursday, 4 November 2010

Page 27: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Test Data Builderpublic 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

Page 28: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 29: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Try: One assertion per test

29

Thursday, 4 November 2010

Page 30: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 31: 2010.10.30 steven sustaining tdd   agile tour shenzhen

At least: One concept per test

31

Thursday, 4 November 2010

Page 32: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 33: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 34: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Describe what happenedassertTrue(“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

Page 35: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Brittle Tests

35

Thursday, 4 November 2010

Page 36: 2010.10.30 steven sustaining tdd   agile tour shenzhen

DRYLetʼ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

Page 37: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 38: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 39: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Mock Overload

• Excessive use of mocks and expectations- perhaps a design issue, are you following SRP?

39

Thursday, 4 November 2010

Page 40: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 41: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 42: 2010.10.30 steven sustaining tdd   agile tour shenzhen

Not testable?

42

•Do you follow good design principles?

Thursday, 4 November 2010

Page 43: 2010.10.30 steven sustaining tdd   agile tour shenzhen

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

Page 44: 2010.10.30 steven sustaining tdd   agile tour shenzhen

44

Doing it better is not harder.Itʼs easier - do it better!

Thank you!

Thursday, 4 November 2010