Eduardo GuerraTDD STEPPATTERNS
Every TDD cycle is astep in direction ofthe desiredfunctionality.
But the path isusually not linear...
Not at all...
There are different kinds ofsteps which can be appliedin different orders...
What test shouldI introduce now   to evolve my functionality?
The TDD step patternshelp you to understandthe kinds of steps that         you can make
It is important tounderstant how the testintroduced willguide theproduction codetowards the desiredfunctionality
APIDEFINITION
How do youtest what youcant see?
You first need to definehow the surface look like,to verify what is inside!
You want to       ...but the testintroduce the     should verifynew elements...   functionality.
How should Iintroduce a new programming    element?
Create the simplest possible    test scenario using the new    elements and do a trivial    implementation.The goal of thi...
Use parameters that willmethod   induce a trivial return.         Test the expectedclass    behavior when the class       ...
In this test scenario,                the return is the String                 that is passed as the                      ...
@Testpublic void disconnected(){   Conection c = new Connection();   assertFalse(c.isConnected());}                   When...
After the test, the class andmethods are created with a      trivial implementation.
And when I dont have           a simple scenario?Fake the implementationreturning a fixed value expected by the test.
DIFERENTIAL TEST
If you writea new successfull test, itdoes not motivate anychange on the source code.
If you add a complex test,   you lose the quick     feedback rithm.
How to increment afunctionality?
Add a test that induce a    small increment on the    current class functionality.The goal of this step is to move forward...
FAKED  Previous Test should return true     with this newtest you will need    to handle this                          Nex...
Equivalence class partitions are   intervals where the class      behavior is similar.should do X                  should ...
To increment functionality,  the test need to jump to      another equivalence                 partition!
@Test public void emptyStack(){   Stack s = new Stack();   assertTrue(s.isEmpty());   assertEquals(0, s.size());}         ...
Test the      Test with   Test withempty class   one entry    multiple                            entries 0              1...
0            1               *Create      Introduce    Completeclass API   basic flow    behavior
A complex scenariocan be created, butadding a singlething in comparisonto the previousones.
EXCEPTIONAL LIMIT
TDD is a happy process          when you add          continouslly functionalityBut you need to think  about the scenarios...
How to definewhen my class do not work?
Add a test that introduce an   invalid scenario and verify if   the class behaves accordingly.The goal of this step is to ...
Here myclass works!                 Here my class               raises an error...
Here my class           raises an error According to TDD principles, that willonly be implemented if a test is created.
@Test(expected=EmptyStackException.class)public void removeFromEmptyStack()             throws EmptyStackException {   Sta...
@Testpublic void addOnFullStack()              throws FullStackException {   Stack s = new Stack(10);   for(int i=0;i<10;i...
EVERYTHINGWORKINGTOGETHER
On TDD, functionality       is tested and introduced little by               little.
Every testfocus on a scenario thatexercises a singlefunctionality.
But how they should   work on a mixed          scenario?
How to make sure       thatfunctionalities areworking together?
Add a test scenario in which     two or more features are     used combined. The goal of this step is to verify ifthe feat...
Special              CompanyAccount               AccountFeatures              Features           Company            Speci...
When you are doing  this kind of step,there is no problem  to create a tests   that are already           green.
@Test public void coupon(){   ShoppingCart s = new ShoppingCart();   s.addItem(“Product“,1000);   s.addCoupon(100,“2347349...
@Test public void couponWithDiscount(){   ShoppingCart s = new ShoppingCart();   s.addItem(“Product“,1000);   s.addCoupon(...
PAUSE FORHOUSEKEEPING
Sometimes the solution is not suitable for the next test.
What can I do whenthe simplest solutionis not suitable for the next requirements?
Ignore temporarely the     current test and refactor the     code to a more suitable     solution.  The goal of this step ...
Dont destroy everything to restart from the scratch...
Perform the change onsmall steps and run the  tests between them.
For some time there will be two  solutions or data structures     doing the same thing.
When the new solution isready, remove completelythe old solution.
After the refactoring,remove the ignore from the    test and move on!
You realise thatfor the next test youshould use a threeinstead of a list.
Create the new data structureAdd code to populate the treeAdd code to use data from the treeDelete the old solution
DIVE DEEP
Sometimes you        need to implement              a complicated                         logic...If I have an auxiliary  ...
You can also feelthat this code doesnot belong to theclass that you aredeveloping.
What can I do when Ifeel that an auxiliary code would help onthe implementation?
Stop temporarely the current     TDD session and dive on another     TDD session to develop the     auxiliary code. The go...
Class A TDD Session    STOP         I need a       function that       break strings      that use camel           case...
Class A TDD SessionClass B TDD Session                         Now I can                       explore all the            ...
I can relax and                               continue my                              TDD knowing                        ...
When you go deep, you can focus on different scenarios, and don`t need to include allof them on the main class test
MOCK COMPLEXITY
My class needs touse functions froma hardware...
My class needs to access a remote         server...
What can I do when it is realy hard to test something that my class needs to do?
Create a test that defines a     mock object that mimic the     behavior responsible for the     complicated part.The goal...
Hard to test! Test                           Message Server                   The tested classBusiness           needs to ...
Lets model this              class as with            another class that Test      sends the message                   to ...
Now it is easy to           replace Message Test      Sender by a mock                object!Business Class            MOCK
final MessageSender mock=         ctx.mock(MessageSender.class);Business b = new Business(mock);ctx.checking(new Expectati...
Can I mock theAPIs instead ofcreating a new    class?
QueueConnectionFactory f = new QueueConnectionFactory();QueueConnection conn = f.createQueueConnection();QueueSession sess...
By creating a new class you  decouple your business classand implement a perfect match    of your application needs.
And how do I test the classthat I mocked?
The test for the class “hardto test“ may be manualYou can incude the test ofthis part on functional testsIf you decide to ...
DEPENDENCE EXPOSURE
Using TDD we are modeling     alone classes...
But to design a objectoriented software you need to      define relationships and                colaboration!
There are                  dependencies                 that the class                wants to hide...… and othersthat it ...
How can I drive myclass using tests to define an explicit   dependency?
Create a test that defines a    mock object that expects calls    according to the dependency    interface.The goal is to ...
Sometimes you know byyour architecture that you  should decouple classes.Business             Database Rules              ...
Authentication       The class can        Service                         also be composed                             by ...
Scheduler                anything  Another times, you are  defining a hotspot andshould be prepared to deal        with an...
By defining the mock, youdefine the API and dividethe responsibilities among              the classes.
final Task t = ctx.mock(Task.class);final Scheduler s = new Scheduler();ctx.checking(new Expectations() {{  one(t).init(s....
final Task t = ctx.mock(Task.class);final Scheduler s = new Scheduler();ctx.checking(new Expectations() {{  one(t).init(s....
BUG LOCATOR
Do you think that you    are protected fromerrors just because you        are using TDD?
A bug can come from ascenario that was not      included on the           test suite!
How should Ihandle bugs when Im using TDD?
Create a test that simulates the    bug scenario and fail because    of it. After that, fix the code to    make the test p...
When a bug is found,the first impulse is to  go straight to thecode and try to fix it!
If a bug appear it isbecause the testsare not coveringthat scenario.So, the first thing that you need  to do is to create ...
If you find other things wrong     on the code, do not start              digging deep to                     solve all   ...
KEEPCALM  ANDCREATE TESTS
Avoid the shortblanket effect!
THE STEPSTOGETHER
to introduce a                        programing element                                           when a bug             ...
Upcoming SlideShare
Loading in...5
×

TDD step patterns

2,069

Published on

Presentation made on SugarLoafPLoP 2012

0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,069
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
0
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

TDD step patterns

  1. 1. Eduardo GuerraTDD STEPPATTERNS
  2. 2. Every TDD cycle is astep in direction ofthe desiredfunctionality.
  3. 3. But the path isusually not linear...
  4. 4. Not at all...
  5. 5. There are different kinds ofsteps which can be appliedin different orders...
  6. 6. What test shouldI introduce now to evolve my functionality?
  7. 7. The TDD step patternshelp you to understandthe kinds of steps that you can make
  8. 8. It is important tounderstant how the testintroduced willguide theproduction codetowards the desiredfunctionality
  9. 9. APIDEFINITION
  10. 10. How do youtest what youcant see?
  11. 11. You first need to definehow the surface look like,to verify what is inside!
  12. 12. You want to ...but the testintroduce the should verifynew elements... functionality.
  13. 13. How should Iintroduce a new programming element?
  14. 14. Create the simplest possible test scenario using the new elements and do a trivial implementation.The goal of this step is to define the API and how the class clients will interact with it.
  15. 15. Use parameters that willmethod induce a trivial return. Test the expectedclass behavior when the class is just created.
  16. 16. In this test scenario, the return is the String that is passed as the argument.@Testpublic void simpleCamelCase(){ String s = “common“; String r = splitCamelCase(s); assertEquals(s,r);}
  17. 17. @Testpublic void disconnected(){ Conection c = new Connection(); assertFalse(c.isConnected());} When a new Connection is created, it is initally disconnected.
  18. 18. After the test, the class andmethods are created with a trivial implementation.
  19. 19. And when I dont have a simple scenario?Fake the implementationreturning a fixed value expected by the test.
  20. 20. DIFERENTIAL TEST
  21. 21. If you writea new successfull test, itdoes not motivate anychange on the source code.
  22. 22. If you add a complex test, you lose the quick feedback rithm.
  23. 23. How to increment afunctionality?
  24. 24. Add a test that induce a small increment on the current class functionality.The goal of this step is to move forward on the TDD session, incrementing functionality.
  25. 25. FAKED Previous Test should return true with this newtest you will need to handle this Next Test should return false
  26. 26. Equivalence class partitions are intervals where the class behavior is similar.should do X should do Z should do Y
  27. 27. To increment functionality, the test need to jump to another equivalence partition!
  28. 28. @Test public void emptyStack(){ Stack s = new Stack(); assertTrue(s.isEmpty()); assertEquals(0, s.size());} Small increment!@Test public void pushOneElement(){ Stack s = new Stack(); s.push("item"); assertFalse(s.isEmpty()); assertEquals(1, s.size());}
  29. 29. Test the Test with Test withempty class one entry multiple entries 0 1 *
  30. 30. 0 1 *Create Introduce Completeclass API basic flow behavior
  31. 31. A complex scenariocan be created, butadding a singlething in comparisonto the previousones.
  32. 32. EXCEPTIONAL LIMIT
  33. 33. TDD is a happy process when you add continouslly functionalityBut you need to think about the scenariosthat your class wont work properly
  34. 34. How to definewhen my class do not work?
  35. 35. Add a test that introduce an invalid scenario and verify if the class behaves accordingly.The goal of this step is to addon the class the capability tohandle exceptional situations.
  36. 36. Here myclass works! Here my class raises an error...
  37. 37. Here my class raises an error According to TDD principles, that willonly be implemented if a test is created.
  38. 38. @Test(expected=EmptyStackException.class)public void removeFromEmptyStack() throws EmptyStackException { Stack s = new Stack(); s.pull();} Here expected can be used because exception can be raised in only one place!
  39. 39. @Testpublic void addOnFullStack() throws FullStackException { Stack s = new Stack(10); for(int i=0;i<10;i++) s.push(“item”+i); try{ s.push(“overload”); fail(); }catch(FullStackException e){}} Here exceptions can be thrown before, and only the expected point should be verified.
  40. 40. EVERYTHINGWORKINGTOGETHER
  41. 41. On TDD, functionality is tested and introduced little by little.
  42. 42. Every testfocus on a scenario thatexercises a singlefunctionality.
  43. 43. But how they should work on a mixed scenario?
  44. 44. How to make sure thatfunctionalities areworking together?
  45. 45. Add a test scenario in which two or more features are used combined. The goal of this step is to verify ifthe features already implemented are working together.
  46. 46. Special CompanyAccount AccountFeatures Features Company Special Account
  47. 47. When you are doing this kind of step,there is no problem to create a tests that are already green.
  48. 48. @Test public void coupon(){ ShoppingCart s = new ShoppingCart(); s.addItem(“Product“,1000); s.addCoupon(100,“23473495734957“); assertEquals(900, s.total());} Different features!@Test public void discount(){ ShoppingCart s = new ShoppingCart(); s.addItem(“Product“,1000); s.addDiscount(0.15); assertEquals(850, s.total());}
  49. 49. @Test public void couponWithDiscount(){ ShoppingCart s = new ShoppingCart(); s.addItem(“Product“,1000); s.addCoupon(100,“23473495734957“); s.addDiscount(0.15); assertEquals(“Coupon before discount“ 765, s.total());}
  50. 50. PAUSE FORHOUSEKEEPING
  51. 51. Sometimes the solution is not suitable for the next test.
  52. 52. What can I do whenthe simplest solutionis not suitable for the next requirements?
  53. 53. Ignore temporarely the current test and refactor the code to a more suitable solution. The goal of this step is to workinternally on the class to provide a better solution for the next requirements.
  54. 54. Dont destroy everything to restart from the scratch...
  55. 55. Perform the change onsmall steps and run the tests between them.
  56. 56. For some time there will be two solutions or data structures doing the same thing.
  57. 57. When the new solution isready, remove completelythe old solution.
  58. 58. After the refactoring,remove the ignore from the test and move on!
  59. 59. You realise thatfor the next test youshould use a threeinstead of a list.
  60. 60. Create the new data structureAdd code to populate the treeAdd code to use data from the treeDelete the old solution
  61. 61. DIVE DEEP
  62. 62. Sometimes you need to implement a complicated logic...If I have an auxiliary method or a helper class...
  63. 63. You can also feelthat this code doesnot belong to theclass that you aredeveloping.
  64. 64. What can I do when Ifeel that an auxiliary code would help onthe implementation?
  65. 65. Stop temporarely the current TDD session and dive on another TDD session to develop the auxiliary code. The goal of this step is to change the focus of the TDD session to allow the developer to work on acode out of the current class scope.
  66. 66. Class A TDD Session STOP I need a function that break strings that use camel case...
  67. 67. Class A TDD SessionClass B TDD Session Now I can explore all the possibilities on camel case!
  68. 68. I can relax and continue my TDD knowing that camel case is workingClass A TDD Session Class B TDD Session
  69. 69. When you go deep, you can focus on different scenarios, and don`t need to include allof them on the main class test
  70. 70. MOCK COMPLEXITY
  71. 71. My class needs touse functions froma hardware...
  72. 72. My class needs to access a remote server...
  73. 73. What can I do when it is realy hard to test something that my class needs to do?
  74. 74. Create a test that defines a mock object that mimic the behavior responsible for the complicated part.The goal is to decouple your main logic from the access to external resources, defining which functionalities you need from it.
  75. 75. Hard to test! Test Message Server The tested classBusiness needs to send a Class message to a Queue.
  76. 76. Lets model this class as with another class that Test sends the message to it. Message ServerBusiness Message Class Sender
  77. 77. Now it is easy to replace Message Test Sender by a mock object!Business Class MOCK
  78. 78. final MessageSender mock= ctx.mock(MessageSender.class);Business b = new Business(mock);ctx.checking(new Expectations() {{ one(mock).send(“message“); will(returnValue(true));}});boolean ret = b.businessMethod();assertTrue(ret);Include on the mock theservices that you need!
  79. 79. Can I mock theAPIs instead ofcreating a new class?
  80. 80. QueueConnectionFactory f = new QueueConnectionFactory();QueueConnection conn = f.createQueueConnection();QueueSession session = conn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);Queue q = new Queue("world");QueueSender sender = session.createSender(q);TextMessage msg = session.createTextMessage();msg.setText(parameter);sender.send(msg);MOCK THIS
  81. 81. By creating a new class you decouple your business classand implement a perfect match of your application needs.
  82. 82. And how do I test the classthat I mocked?
  83. 83. The test for the class “hardto test“ may be manualYou can incude the test ofthis part on functional testsIf you decide to automatethe test, you will need tohandle this only once.
  84. 84. DEPENDENCE EXPOSURE
  85. 85. Using TDD we are modeling alone classes...
  86. 86. But to design a objectoriented software you need to define relationships and colaboration!
  87. 87. There are dependencies that the class wants to hide...… and othersthat it needsto expose.
  88. 88. How can I drive myclass using tests to define an explicit dependency?
  89. 89. Create a test that defines a mock object that expects calls according to the dependency interface.The goal is to model the contract between both classes, defining which methods are needed and when they will be called.
  90. 90. Sometimes you know byyour architecture that you should decouple classes.Business Database Rules Access
  91. 91. Authentication The class can Service also be composed by different implementations. card fingerprintvalidator validator
  92. 92. Scheduler anything Another times, you are defining a hotspot andshould be prepared to deal with anything.
  93. 93. By defining the mock, youdefine the API and dividethe responsibilities among the classes.
  94. 94. final Task t = ctx.mock(Task.class);final Scheduler s = new Scheduler();ctx.checking(new Expectations() {{ one(t).init(s.getConfig()); one(t).execute();}});s.schedule(t, 100);Thread.sleep(110);
  95. 95. final Task t = ctx.mock(Task.class);final Scheduler s = new Scheduler();ctx.checking(new Expectations() {{ one(t).init(s.getConfig()); exactly(2).of(t).execute(); will(onConsecutiveCalls( throwException(new RuntimeException()), returnValue(null));}});s.schedule(t, 100);Thread.sleep(110);
  96. 96. BUG LOCATOR
  97. 97. Do you think that you are protected fromerrors just because you are using TDD?
  98. 98. A bug can come from ascenario that was not included on the test suite!
  99. 99. How should Ihandle bugs when Im using TDD?
  100. 100. Create a test that simulates the bug scenario and fail because of it. After that, fix the code to make the test pass. The goal is to locate the bugusing the tests and to make sure that a similar problem will not return in the future.
  101. 101. When a bug is found,the first impulse is to go straight to thecode and try to fix it!
  102. 102. If a bug appear it isbecause the testsare not coveringthat scenario.So, the first thing that you need to do is to create the tests!
  103. 103. If you find other things wrong on the code, do not start digging deep to solve all of them !
  104. 104. KEEPCALM ANDCREATE TESTS
  105. 105. Avoid the shortblanket effect!
  106. 106. THE STEPSTOGETHER
  107. 107. to introduce a programing element when a bug is found Bug to continue Locator API to improve the code Definition Exceptional to introduce Limit funtionality to introduce to define a programing exceptional element scenarios Dive to add more Everything Deep functionality Differential Working to consolidate Test Together features if you need auxiliary code if the previous solution is not suitable Pause for if something is Mock hard to test HousekeepingComplexity to define dependences API Dependence Exposure

×