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

TDD And Refactoring

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

Editor's Notes

  • #2 In this presentation, we will try to cover three things: Explain what is TDD and its potential benefits (i.e. TDD in theory) Discuss real-life obstacles we most likely encounter while adopting TDD (i.e. TDD in practice) Role of AS APD (A)TDD champions