The document discusses Test-Driven Development (TDD) and refactoring, outlining the principles and methodologies involved in both practices. It emphasizes TDD's micro-cycle, the importance of writing tests before production code, and various refactoring techniques to improve software design and maintainability. Key concepts include composition over inheritance, dependency injection, and specific refactoring strategies like sprouting methods and classes.
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
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.
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(); } }
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