Upload
agiletourchina
View
753
Download
1
Embed Size (px)
DESCRIPTION
Citation preview
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
Agenda
•Test-Driven Development in 1 slide•Readability•Modifying tons of tests whenever we change code?!
3
Thursday, 4 November 2010
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”)2. Code (to make test pass “green”)3. Refactor (test still passes “green”)
5
Thursday, 4 November 2010
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
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)
9
Thursday, 4 November 2010
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 characteristics of any input values- Anything relevant about the state
• Output- The outputs expected- The expected post-exercise state
11
Thursday, 4 November 2010
TestDox convention
public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […]
12
Credit: Growing OO Software, Guided by Tests
What it does?
Thursday, 4 November 2010
TestDox convention
public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […]
13
Credit: Growing OO Software, Guided by Tests
Pre-condition / Input
Thursday, 4 November 2010
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 parallel source tree
15
Thursday, 4 November 2010
Test case classes
•Test case class per class?•Test case class per feature?•Test case class per fixture?
16
Thursday, 4 November 2010
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
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
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
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
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 November 2010
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
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
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
Test Data Buildernew OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode().build()) .build()) .build();
26
Thursday, 4 November 2010
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
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
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* 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
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 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
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
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
Brittle Tests
35
Thursday, 4 November 2010
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
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
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
Mock Overload
• Excessive use of mocks and expectations- perhaps a design issue, are you following SRP?
39
Thursday, 4 November 2010
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
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
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 - 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
Doing it better is not harder.Itʼs easier - do it better!
Thank you!
Thursday, 4 November 2010