Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

TDD And Refactoring


Published on

Ganesan Rajamani's presentation on Test Driven Development and Refactoring. Was presented at the Agile Goa 2008 conference.

Published in: Technology, Business
  • Be the first to comment

TDD And Refactoring

  1. 1. TDD and Refactoring Ganesan R Sr.Software Developer Sabre Holdings
  2. 2. Game Plan <ul><li>Introduction (A Little Bit of Theory) </li></ul><ul><li>TDD Basics </li></ul><ul><li>Guidelines for Testable Design </li></ul><ul><li>Refactoring and its Techniques </li></ul>
  3. 3. Introduction Confidential
  4. 4. What is TDD? <ul><li>A Simple Definition </li></ul><ul><ul><li>Write a Failing (Automated) Test Before Writing Production Code </li></ul></ul><ul><ul><li>Make a Minimal Change to Production Code to Fix the Failing Test </li></ul></ul><ul><ul><li>When There are Enough Tests, Re-factor the code </li></ul></ul><ul><ul><ul><li>Primary Goals: Simplicity, Readability & No Duplication </li></ul></ul></ul><ul><ul><ul><li>Reliance Upon Automated Test Safety Net </li></ul></ul></ul><ul><ul><ul><li>Both Production & Test Code </li></ul></ul></ul><ul><li>Two Primary Goals of Writing Tests </li></ul><ul><ul><li>Safety Net </li></ul></ul><ul><ul><li>Documentation </li></ul></ul>
  5. 5. Testing Terminology
  6. 6. TDD: The Micro-Cycle of Agile Development Process
  7. 7. TDD: The Micro-Cycle of Agile Development Process
  8. 8. TDD Basics Confidential
  9. 9. TDD Basics (Discussion & Demo) <ul><li>Good Test is Atomic & Isolated </li></ul><ul><li>Decomposing Requirements Into a Test List </li></ul><ul><li>Programming by Intention </li></ul><ul><ul><li>Making the Compiler Happy </li></ul></ul><ul><ul><li>Running the Failing Test </li></ul></ul><ul><ul><li>Making the Test Pass </li></ul></ul><ul><ul><li>Repeating it Again for Other Tests In the List </li></ul></ul><ul><li>Breadth-First vs. Depth-First </li></ul><ul><li>Let’s Not Forget to Re-factor </li></ul><ul><ul><li>Both Production & Test Code Re-factoring </li></ul></ul><ul><ul><li>Remove Duplication </li></ul></ul><ul><ul><li>Re-factoring toward smaller methods </li></ul></ul><ul><ul><li>Keeping things in balance </li></ul></ul>
  10. 10. TDD Concepts & Patterns <ul><li>What to Test & in What Order? </li></ul><ul><ul><li>Details vs. big picture </li></ul></ul><ul><ul><li>Uncertain vs. familiar </li></ul></ul><ul><ul><li>High value vs. low-hanging fruit </li></ul></ul><ul><ul><li>Happy path vs. error situations </li></ul></ul><ul><li>Implementation Strategies </li></ul><ul><ul><li>Faking it </li></ul></ul><ul><ul><li>Triangulation </li></ul></ul><ul><ul><li>Obvious Implementation </li></ul></ul><ul><li>Prime Guidelines for Test-Driving </li></ul><ul><ul><li>Do Not Skip Re-factoring </li></ul></ul><ul><ul><li>Get to Green Fast </li></ul></ul><ul><ul><li>Slow Down After a Mistake </li></ul></ul>
  11. 11. TDD Concepts & Patterns (Continued) <ul><li>Unit-Testing Concepts </li></ul><ul><ul><li>Using Test Fixtures </li></ul></ul><ul><ul><li>Using Test Doubles (More Details to Follow) </li></ul></ul>
  12. 12. Test Doubles (Alternative Implementations) <ul><li>An Example of a Test Double </li></ul><ul><li>Reasons for Having Test Doubles </li></ul><ul><ul><li>Avoiding a Landslide of Failing Tests </li></ul></ul><ul><ul><li>Avoiding Slow Running Tests </li></ul></ul><ul><ul><li>Avoiding Availability (Existence) Problems </li></ul></ul><ul><ul><li>Avoiding Difficult Instantiation And/Or Configuration </li></ul></ul><ul><li>Test Double Taxonomy </li></ul><ul><ul><li>Stubs </li></ul></ul><ul><ul><li>Fakes </li></ul></ul><ul><ul><li>Mocks </li></ul></ul><ul><li>Exercise </li></ul>
  13. 13. Point Of Sale System… <ul><li>As an example, we’ve chosen a point-of-sale system, like one might encounter in any retail store. A sales clerk passes items over a scanner that reads the barcode. A display monitor shows information on each item as it is scanned and also tracks the total for each sale of one or more items to a given shopper. </li></ul><ul><li>Sample User Story </li></ul><ul><ul><li>The total price of all items in the sale is available. </li></ul></ul>
  14. 14. Guidelines for Testable Design Confidential
  15. 15. Guidelines for Testable Design <ul><li>Choose composition over inheritance </li></ul><ul><li>Avoid static and the Singleton </li></ul><ul><li>Isolate dependencies </li></ul><ul><li>Inject dependencies </li></ul>
  16. 16. Choose Composition Over inheritance <ul><li>Inheriting lets subclass to inherit all the functionality of Superclass. </li></ul><ul><li>Downside – Introduce inconvenient constraints related to Instantiating the subclass in test harness. </li></ul><ul><li>Composition allows more flexible design solution for reusability. </li></ul><ul><li>Example – Allows to instantiate the composite object with alternative implementations </li></ul>
  17. 17. Dependency Injection <ul><li>Refers to supplying an external dependency to a software component. </li></ul><ul><li>Forms of Dependency Injection – </li></ul><ul><ul><li>interface injection , in which the exported module provides an interface that its users must implement in order to get the dependencies at runtime </li></ul></ul><ul><ul><li>setter injection , in which the dependent module exposes a setter method which the framework uses to inject the dependency . </li></ul></ul><ul><ul><li>constructor injection , in which the dependencies are provided through the class constructor. </li></ul></ul>
  18. 18. Constructor Injection.. <ul><li>public class ImportantClass { </li></ul><ul><li>IFoo foo; </li></ul><ul><li>public ImportantClass() </li></ul><ul><li>{ </li></ul><ul><ul><li> = new EnterpriseFoo(); </li></ul></ul><ul><li>} </li></ul><ul><li>void doReallyImportantStuff() { </li></ul><ul><li>; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>public class ImportantClass { </li></ul><ul><li>IFoo foo; </li></ul><ul><li>public ImportantClass(IFoo foo) { = foo; </li></ul><ul><li>} </li></ul><ul><li>void doReallyImportantStuff() { </li></ul><ul><li>; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  19. 19. Refactoring Confidential
  20. 20. What is Refactoring? <ul><li>Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. </li></ul><ul><li>Its heart is a series of small behavior preserving transformations. </li></ul>
  21. 21. What is Refactoring? <ul><li>Each transformation (called a 'Refactoring') does little, but a sequence of transformations can produce a significant restructuring. </li></ul><ul><li>The system is also kept fully working after each small Refactoring, reducing the chances that a system can get seriously broken during the restructuring. </li></ul>
  22. 22. Why Do we refactor ? <ul><li>Improves the design of the software. </li></ul><ul><li>Easier to maintain and understand. </li></ul><ul><li>Easier to facilitate change. </li></ul><ul><li>More flexibility. </li></ul><ul><li>Increased reusability. </li></ul><ul><li>To help find bugs </li></ul>
  23. 23. When do we refactor ? <ul><li>Duplicated code. </li></ul><ul><li>Long method. </li></ul><ul><li>Long parameter list.. </li></ul><ul><li>Improper naming. </li></ul>
  24. 24. Refactoring Techniques <ul><li>Here are some of the Refactoring techniques discussed in the session </li></ul><ul><ul><ul><li>Sprout Method </li></ul></ul></ul><ul><ul><ul><li>Sprout Class </li></ul></ul></ul><ul><ul><ul><li>Wrap Method </li></ul></ul></ul><ul><ul><ul><li>Wrap Class </li></ul></ul></ul>
  25. 25. Sprout Method <ul><li>While adding new feature to the existing method it can formulated completely as a new method. How ? </li></ul><ul><ul><ul><li>Write the code in the new method. </li></ul></ul></ul><ul><ul><ul><li>Call it from the places where the new functionality needs to be </li></ul></ul></ul><ul><li>Example: </li></ul><ul><ul><ul><li>Public class TransactionGate </li></ul></ul></ul><ul><ul><ul><li>{ </li></ul></ul></ul><ul><ul><ul><li>Public void postEntries(List entries){ </li></ul></ul></ul><ul><ul><ul><li>for(Iterator it=entries.iterator();it.hasNext();){ </li></ul></ul></ul><ul><ul><ul><li>Entry entry=(Entry); </li></ul></ul></ul><ul><ul><ul><li>entry.postDate(); </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>transactionBundle.getListManager.add(entries) ; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  26. 26. Sprout method - Continue <ul><ul><ul><li>Public class TransactionGate </li></ul></ul></ul><ul><ul><ul><li>{ </li></ul></ul></ul><ul><ul><ul><li>Public void postEntries(List entries){ </li></ul></ul></ul><ul><ul><ul><li>List entriesToAdd=uniqueEntries(entries); </li></ul></ul></ul><ul><ul><ul><li>-------- </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>transactionBundle.getListManager.add(entries) ; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>List uniqueEntries(List entries) { </li></ul></ul></ul><ul><ul><ul><li>//Unique Entries impl comes here </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul>
  27. 27. Sprout method - steps <ul><li>Identify the place to make the code change </li></ul><ul><li>If the change can be formulated as a single sequence of statement write down a call for the new method that will do the work involved and comment it out. </li></ul><ul><li>Determine the local variables you need from the source method and make them arguments for the call. </li></ul>
  28. 28. Sprout method - steps <ul><li>Determine whether the sprouted method will need to return values to source method. If so change the call so that its return value is assigned to a variable. </li></ul><ul><li>Develop the sprout method using TDD. </li></ul><ul><li>Remove the comment in the source code to enable the call. </li></ul>
  29. 29. Sprout Class <ul><li>Sprout method is powerful but in some tangled dependency situation it is not powerful though </li></ul><ul><li>Example: </li></ul><ul><li>std::string QuaterlyReportGenerator::generate() </li></ul><ul><li>{ </li></ul><ul><li>std::veactor<Result> results=database.queryResults(beginDate,endDate) ; </li></ul><ul><li>std::string pageText ; </li></ul><ul><li>pageText+=“<html><head><title>Quaterly Report</title></head> </li></ul><ul><li><body><table>” </li></ul><ul><li>if(results.size()!=0){ </li></ul><ul><li>//html page generator code comes here </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  30. 30. Sprout class - Continues <ul><li>Suppose if we need to add a new functionality. </li></ul><ul><ul><ul><li>Add a Header row for the HTML table its producing. </li></ul></ul></ul><ul><ul><ul><li>“ QuaterlyReportGenerator” is a huge class to get into test harness. </li></ul></ul></ul><ul><li>Formulate the new change into a little class and bring it in test harness. </li></ul><ul><li>class QuaterlyReportTableHeaderGenerator{ </li></ul><ul><li>public: </li></ul><ul><li>string generate() ; </li></ul><ul><li>} </li></ul>
  31. 31. Sprout class - continues <ul><li>Move the generate method to a interface. </li></ul><ul><li>Class HTMLGenerator{ </li></ul><ul><li>public : </li></ul><ul><li>virtual ~HTMLGenerator() ; </li></ul><ul><li>virtual string generate() ; </li></ul><ul><li>} </li></ul><ul><li>Make QuaterlyReportGenerator and QuaterlyReportTableHeaderGenerator inherit from HTMLGenerator. </li></ul><ul><li>Now the new class is in testharness at somepoint in time we would be able to get the QuaterlyReportGenerator also in test harness. </li></ul>
  32. 32. Sprout class - steps <ul><li>Identify where you need to make the code change. </li></ul><ul><li>Think of a good name for the class, create an object of the class and call the method that will do the work ; then comment the lines. </li></ul><ul><li>Determine the local variables you need from the source method and make them as constructor arguments. </li></ul>
  33. 33. Sprout class - steps <ul><li>Determine whether the sprouted class will need to return value to the source method. </li></ul><ul><li>If so, provide a method in the class that will supply those values and add a call to the source method to receive the same. </li></ul><ul><li>Develop the sprout class test first. </li></ul>
  34. 34. Further.. <ul><li>Recommended reading </li></ul><ul><ul><ul><li>Working Effective with Legacy code By Michael Feathers </li></ul></ul></ul><ul><ul><ul><li> </li></ul></ul></ul><ul><ul><ul><li>Refactoring: Improving the Design of Existing Code – Martin Fowler </li></ul></ul></ul><ul><ul><ul><li> </li></ul></ul></ul><ul><ul><ul><li> </li></ul></ul></ul>