SlideShare une entreprise Scribd logo
1  sur  44
Télécharger pour lire hors ligne
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++,
                            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)
                 Iteration start




                                                                                                 Iteration end
                                       Integrate           Integrate   Integrate




                                                                                                                 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() { […]




                What it does?

         Credit: Growing OO Software, Guided by Tests


                                                                                12

Thursday, 4 November 2010
TestDox convention

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




                                                        Pre-condition / Input

         Credit: Growing OO Software, Guided by Tests


                                                                                13

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


                                                                                              18

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
Example
                 TEST(LightScheduler, ScheduleOffWeekendAndItsSaturdayAndItsTime)
                 {
                   LightScheduler_ScheduleTurnOff(lightNumber, WEEKEND, scheduledMinute);
                   whenItBecomes(SATURDAY, scheduledMinute);
                   thenExpect(lightNumber, LIGHT_OFF);
                 }




         Credit: Test Driven Development for Embedded C


                                                                                            20

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
                 @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


                                                                                      23

Thursday, 4 November 2010
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


                                                                                         24

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 Builder
               new OrderBuilder()
               
    .fromCustomer(
               
    
    new CustomerBuilder()
               
    
    
    .withAddress(new AddressBuilder().withNoPostcode().build())
               
    
    
    .build())
               
    .build();




                                                                                            26

Thursday, 4 November 2010
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
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/
                                                                                         28

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
              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/                   32

Thursday, 4 November 2010
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


                                                                       33

Thursday, 4 November 2010
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


                                                              34

Thursday, 4 November 2010
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!”
                        “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
                   • 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




                                                                                                 37

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
                                                       FRIENDS




                                                                                             40

Thursday, 4 November 2010
Indirection
                   • Assign the responsibility to an intermediate object to mediate between
                       other components or services so that they are not directly coupled




                                                                                              41

Thursday, 4 November 2010
Not testable?
               • Do you follow good design principles?




                                                         42

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
Doing it better is not harder.
                              Itʼs easier - do it better!




                                    Thank you!
                                                             44

Thursday, 4 November 2010

Contenu connexe

Similaire à 2010.10.30 steven sustaining tdd agile tour shenzhen

Sustainable TDD
Sustainable TDDSustainable TDD
Sustainable TDD
Steven Mak
 
Sdforum 11-04-2010
Sdforum 11-04-2010Sdforum 11-04-2010
Sdforum 11-04-2010
Ted Dunning
 
Driving Quality with TDD
Driving Quality with TDDDriving Quality with TDD
Driving Quality with TDD
Steven Mak
 
Executable specifications for xtext
Executable specifications for xtextExecutable specifications for xtext
Executable specifications for xtext
meysholdt
 
PHPUnit & Continuous Integration: An Introduction
PHPUnit & Continuous Integration: An IntroductionPHPUnit & Continuous Integration: An Introduction
PHPUnit & Continuous Integration: An Introduction
alexmace
 
Unit Testing Guidelines
Unit Testing GuidelinesUnit Testing Guidelines
Unit Testing Guidelines
Joel Hooks
 

Similaire à 2010.10.30 steven sustaining tdd agile tour shenzhen (20)

Sustainable TDD
Sustainable TDDSustainable TDD
Sustainable TDD
 
2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier2016 10-04: tdd++: tdd made easier
2016 10-04: tdd++: tdd made easier
 
Crowd-sourced Automated Firefox UI Testing
Crowd-sourced Automated Firefox UI TestingCrowd-sourced Automated Firefox UI Testing
Crowd-sourced Automated Firefox UI Testing
 
SD Forum 11 04-2010
SD Forum 11 04-2010SD Forum 11 04-2010
SD Forum 11 04-2010
 
Sdforum 11-04-2010
Sdforum 11-04-2010Sdforum 11-04-2010
Sdforum 11-04-2010
 
Are Your Tests Really Helping You?
Are Your Tests Really Helping You?Are Your Tests Really Helping You?
Are Your Tests Really Helping You?
 
Unit Testing Basics
Unit Testing BasicsUnit Testing Basics
Unit Testing Basics
 
Plone Testing Tools And Techniques
Plone Testing Tools And TechniquesPlone Testing Tools And Techniques
Plone Testing Tools And Techniques
 
Open source bridge testing antipatterns presentation
Open source bridge testing antipatterns presentationOpen source bridge testing antipatterns presentation
Open source bridge testing antipatterns presentation
 
An Introduction to Test Driven Development
An Introduction to Test Driven Development An Introduction to Test Driven Development
An Introduction to Test Driven Development
 
Test Drive Development
Test Drive DevelopmentTest Drive Development
Test Drive Development
 
An Introduction to
An Introduction to An Introduction to
An Introduction to
 
Driving Quality with TDD
Driving Quality with TDDDriving Quality with TDD
Driving Quality with TDD
 
Executable specifications for xtext
Executable specifications for xtextExecutable specifications for xtext
Executable specifications for xtext
 
PHPUnit & Continuous Integration: An Introduction
PHPUnit & Continuous Integration: An IntroductionPHPUnit & Continuous Integration: An Introduction
PHPUnit & Continuous Integration: An Introduction
 
Node.js - A Quick Tour II
Node.js - A Quick Tour IINode.js - A Quick Tour II
Node.js - A Quick Tour II
 
Giving automated tests the love they deserve at Listings
Giving automated tests the love they deserve at ListingsGiving automated tests the love they deserve at Listings
Giving automated tests the love they deserve at Listings
 
TDD - Christchurch APN May 2012
TDD - Christchurch APN May 2012TDD - Christchurch APN May 2012
TDD - Christchurch APN May 2012
 
Unit testing with Junit
Unit testing with JunitUnit testing with Junit
Unit testing with Junit
 
Unit Testing Guidelines
Unit Testing GuidelinesUnit Testing Guidelines
Unit Testing Guidelines
 

Plus de Odd-e

Taking the business along for a ride
Taking the business along for a rideTaking the business along for a ride
Taking the business along for a ride
Odd-e
 
分布式设计团队的敏捷之道
分布式设计团队的敏捷之道分布式设计团队的敏捷之道
分布式设计团队的敏捷之道
Odd-e
 
Scrum敏捷实施实例讲解 out_softingtemplate.ppt_
 Scrum敏捷实施实例讲解 out_softingtemplate.ppt_ Scrum敏捷实施实例讲解 out_softingtemplate.ppt_
Scrum敏捷实施实例讲解 out_softingtemplate.ppt_
Odd-e
 
Terry yin adding unit-test_to_legacy_code
Terry yin   adding unit-test_to_legacy_codeTerry yin   adding unit-test_to_legacy_code
Terry yin adding unit-test_to_legacy_code
Odd-e
 
张克强 敏捷的过程能力
张克强   敏捷的过程能力张克强   敏捷的过程能力
张克强 敏捷的过程能力
Odd-e
 
杨根兴 软件过程改进与敏捷方法
杨根兴   软件过程改进与敏捷方法杨根兴   软件过程改进与敏捷方法
杨根兴 软件过程改进与敏捷方法
Odd-e
 
阳陆育 大型软件产品的敏捷案例分享
阳陆育 大型软件产品的敏捷案例分享阳陆育 大型软件产品的敏捷案例分享
阳陆育 大型软件产品的敏捷案例分享
Odd-e
 
Mike 关于敏捷的一些误解
Mike   关于敏捷的一些误解Mike   关于敏捷的一些误解
Mike 关于敏捷的一些误解
Odd-e
 
Ethan huang 全民qa
Ethan huang   全民qaEthan huang   全民qa
Ethan huang 全民qa
Odd-e
 
Li kai roll-out scrum in an intel organization
Li kai   roll-out scrum in an intel organizationLi kai   roll-out scrum in an intel organization
Li kai roll-out scrum in an intel organization
Odd-e
 
Jackson user story
Jackson   user storyJackson   user story
Jackson user story
Odd-e
 

Plus de Odd-e (20)

打造真正的软件
打造真正的软件打造真正的软件
打造真正的软件
 
培育软件的可测试性
培育软件的可测试性培育软件的可测试性
培育软件的可测试性
 
做一个对产品负责的PO
做一个对产品负责的PO做一个对产品负责的PO
做一个对产品负责的PO
 
庖丁解牛用户故事 (Splitting Your User Story)
庖丁解牛用户故事 (Splitting Your User Story)庖丁解牛用户故事 (Splitting Your User Story)
庖丁解牛用户故事 (Splitting Your User Story)
 
Simplicity (简洁的艺术)
Simplicity (简洁的艺术)Simplicity (简洁的艺术)
Simplicity (简洁的艺术)
 
鱼与熊掌 - 软件质量 vs 交付速度
鱼与熊掌 - 软件质量 vs 交付速度鱼与熊掌 - 软件质量 vs 交付速度
鱼与熊掌 - 软件质量 vs 交付速度
 
Find your mirror
Find your mirror Find your mirror
Find your mirror
 
敏捷教练如何运用欣赏式探询(AI)
敏捷教练如何运用欣赏式探询(AI)敏捷教练如何运用欣赏式探询(AI)
敏捷教练如何运用欣赏式探询(AI)
 
敏捷 - 领导力的救赎
敏捷 - 领导力的救赎敏捷 - 领导力的救赎
敏捷 - 领导力的救赎
 
Taking the business along for a ride
Taking the business along for a rideTaking the business along for a ride
Taking the business along for a ride
 
分布式设计团队的敏捷之道
分布式设计团队的敏捷之道分布式设计团队的敏捷之道
分布式设计团队的敏捷之道
 
Scrum敏捷实施实例讲解 out_softingtemplate.ppt_
 Scrum敏捷实施实例讲解 out_softingtemplate.ppt_ Scrum敏捷实施实例讲解 out_softingtemplate.ppt_
Scrum敏捷实施实例讲解 out_softingtemplate.ppt_
 
Terry yin adding unit-test_to_legacy_code
Terry yin   adding unit-test_to_legacy_codeTerry yin   adding unit-test_to_legacy_code
Terry yin adding unit-test_to_legacy_code
 
张克强 敏捷的过程能力
张克强   敏捷的过程能力张克强   敏捷的过程能力
张克强 敏捷的过程能力
 
杨根兴 软件过程改进与敏捷方法
杨根兴   软件过程改进与敏捷方法杨根兴   软件过程改进与敏捷方法
杨根兴 软件过程改进与敏捷方法
 
阳陆育 大型软件产品的敏捷案例分享
阳陆育 大型软件产品的敏捷案例分享阳陆育 大型软件产品的敏捷案例分享
阳陆育 大型软件产品的敏捷案例分享
 
Mike 关于敏捷的一些误解
Mike   关于敏捷的一些误解Mike   关于敏捷的一些误解
Mike 关于敏捷的一些误解
 
Ethan huang 全民qa
Ethan huang   全民qaEthan huang   全民qa
Ethan huang 全民qa
 
Li kai roll-out scrum in an intel organization
Li kai   roll-out scrum in an intel organizationLi kai   roll-out scrum in an intel organization
Li kai roll-out scrum in an intel organization
 
Jackson user story
Jackson   user storyJackson   user story
Jackson user story
 

2010.10.30 steven sustaining tdd agile tour shenzhen

  • 1. www.odd-e.com | steven@odd-e.com Sustainable Test Driven Development Thursday, 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 2 Thursday, 4 November 2010
  • 3. Agenda • Test-Driven Development in 1 slide • Readability • Modifying tons of tests whenever we change code?! 3 Thursday, 4 November 2010
  • 4. Test Driven Development 4 Thursday, 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”) 5 Thursday, 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 6 Thursday, 4 November 2010
  • 7. Never Skip Refactoring 7 Thursday, 4 November 2010
  • 8. Naming 8 Thursday, 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) 9 Thursday, 4 November 2010
  • 10. Whatʼs wrong? TEST (TEST_AIH, FAIL_BAD_PARAM) 10 Thursday, 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 11 Thursday, 4 November 2010
  • 12. TestDox convention public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […] What it does? Credit: Growing OO Software, Guided by Tests 12 Thursday, 4 November 2010
  • 13. TestDox convention public class ListTests { @Test public void throwsAnExceptionWhenRemovingAnItemItDoesntHold() { […] Pre-condition / Input Credit: Growing OO Software, Guided by Tests 13 Thursday, 4 November 2010
  • 14. Structuring it well 14 Thursday, 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 15 Thursday, 4 November 2010
  • 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. 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. 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 18 Thursday, 4 November 2010
  • 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. Example TEST(LightScheduler, ScheduleOffWeekendAndItsSaturdayAndItsTime) { LightScheduler_ScheduleTurnOff(lightNumber, WEEKEND, scheduledMinute); whenItBecomes(SATURDAY, scheduledMinute); thenExpect(lightNumber, LIGHT_OFF); } Credit: Test Driven Development for Embedded C 20 Thursday, 4 November 2010
  • 21. Question: I have a lot to setup 21 Thursday, 4 November 2010
  • 22. Have your tried fixture? TEST_GROUP (TEST_thisObject) { void setup() { } void teardown() { } }; 22 Thursday, 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 23 Thursday, 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 24 Thursday, 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)); […] } 25 Thursday, 4 November 2010
  • 26. Test Data Builder new OrderBuilder() .fromCustomer( new CustomerBuilder() .withAddress(new AddressBuilder().withNoPostcode().build()) .build()) .build(); 26 Thursday, 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/ 28 Thursday, 4 November 2010
  • 29. Try: One assertion per test 29 Thursday, 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); } } 30 Thursday, 4 November 2010
  • 31. At least: One concept per test 31 Thursday, 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/ 32 Thursday, 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 33 Thursday, 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 34 Thursday, 4 November 2010
  • 35. Brittle Tests 35 Thursday, 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!” ... 36 Thursday, 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 37 Thursday, 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 38 Thursday, 4 November 2010
  • 39. Mock Overload • Excessive use of mocks and expectations - perhaps a design issue, are you following SRP? 39 Thursday, 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 40 Thursday, 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 41 Thursday, 4 November 2010
  • 42. Not testable? • Do you follow good design principles? 42 Thursday, 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 43 Thursday, 4 November 2010
  • 44. Doing it better is not harder. Itʼs easier - do it better! Thank you! 44 Thursday, 4 November 2010