Realistic Test-Driven Development:Paying and PreventingTechnical Debt<br />Rob Myers<br />Agile Development Practices<br /...
11 November 2009<br />© Rob Myers 2009<br />2<br />Unit testing is sooooDEPRESSING<br />
11 November 2009<br />© Rob Myers 2009<br />3<br />TDD is fun,<br />and provides much more than just unit-tests!<br />
11 November 2009<br />© Rob Myers 2009<br />4<br />from<br />XP<br />to<br />ATDD<br />&<br />BDD<br />
11 November 2009<br />© Rob Myers 2009<br />5<br />waste<br />
11 November 2009<br />© Rob Myers 2009<br />6<br />#1<br />automation<br />public static void Main() {<br />Console.WriteL...
11 November 2009<br />© Rob Myers 2009<br />7<br />
11 November 2009<br />© Rob Myers 2009<br />8<br />#2<br />Test-First<br />We write a test before writing the code that ma...
Why Wait?<br />11 November 2009<br />© Rob Myers 2009<br />9<br />Code<br />Test<br />Months<br />Code<br />Test<br />Week...
What If?<br />11 November 2009<br />© Rob Myers 2009<br />10<br />Code<br />Run Test<br />Test<br />Write Test<br />Run Te...
Benefits of Test-First<br />Just-In-Time analysis.<br />We know when something is…<br />…done.<br />…done correctly.<br />...
11 November 2009<br />© Rob Myers 2009<br />12<br />
11 November 2009<br />© Rob Myers 2009<br />13<br />#3<br />Any behavior-preserving change that improves maintainability.<...
11 November 2009<br />© Rob Myers 2009<br />14<br />
11 November 2009<br />© Rob Myers 2009<br />15<br />
11 November 2009<br />© Rob Myers 2009<br />16<br />#4<br />Mock Objects<br />
Prep road-data for new Mars Colony Road/Canal Service<br /><ul><li> Build ‘Earth’ adapter around map-data service
Refactor all callers to use Earth (all?)
Extract abstract  parent ‘Planet’
Planet needs a factory
Test that Mars adapter calls new Mars-map service (mock the service)
Test that Planet factory determines which planet client is on (mock config file)</li></ul>11 November 2009<br />© Rob Myer...
11 November 2009<br />© Rob Myers 2009<br />18<br />Analogies  &  Metaphors<br />
11 November 2009<br />© Rob Myers 2009<br />19<br />
11 November 2009<br />© Rob Myers 2009<br />20<br />
11 November 2009<br />© Rob Myers 2009<br />21<br />“The results of the case studies indicate that the pre-release defect ...
11 November 2009<br />© Rob Myers 2009<br />22<br />real value<br />
11 November 2009<br />© Rob Myers 2009<br />23<br />architectural<br />perspective<br />
11 November 2009<br />© Rob Myers 2009<br />24<br />roadblocks<br />
11 November 2009<br />© Rob Myers 2009<br />25<br />discipline<br />
11 November 2009<br />© Rob Myers 2009<br />26<br />steps<br />Write oneunit test.<br />Build or add to the object under t...
11 November 2009<br />© Rob Myers 2009<br />27<br /> given<br /> when<br /> then<br />
11 November 2009<br />© Rob Myers 2009<br />28<br />TDD Demo<br />
11 November 2009<br />© Rob Myers 2009<br />29<br />Basic UML Class Diagrams<br />Foo<br />- intprivateVariable<br />+ int...
11 November 2009<br />© Rob Myers 2009<br />30<br />Global Currency Money-Market Account<br />
11 November 2009<br />© Rob Myers 2009<br />31<br />Global ATMAccess<br />
Stories<br />As Rob the US account holder, I want to be able to withdraw USD from a US ATM, but select which currency hold...
Primary Objects<br />11 November 2009<br />© Rob Myers 2009<br />33<br />Currency<br />Account<br />Holding<br />
More Detail<br />11 November 2009<br />© Rob Myers 2009<br />34<br />Currency<br />Holding<br />value<br />currency<br />c...
Start Simple<br />To Do<br /><ul><li>When currencies are the same.
When value is zero.</li></ul>11 November 2009<br />© Rob Myers 2009<br />35<br />
Specification, and Interface<br />11 November 2009<br />© Rob Myers 2009<br />36<br />[TestMethod]<br />public void GivesS...
“Thank You, But…”<br />11 November 2009<br />© Rob Myers 2009<br />37<br />using System;<br />class CurrencyConverter {<br...
“…I Want to See it Fail Successfully”<br />11 November 2009<br />© Rob Myers 2009<br />38<br />class CurrencyConverter {<b...
Just Enough to Pass<br />11 November 2009<br />© Rob Myers 2009<br />39<br />public double convert(<br />    double value,...
a.  Refactor Away the Duplication<br />11 November 2009<br />© Rob Myers 2009<br />40<br />[TestMethod]<br />public void G...
b.  Triangulate<br />11 November 2009<br />© Rob Myers 2009<br />41<br />
11 November 2009<br />© Rob Myers 2009<br />42<br />We don’t add any behavior without a failing test…<br />Rodin’s The Thi...
Triangulating Test<br />11 November 2009<br />© Rob Myers 2009<br />43<br />[TestMethod]<br />public void GivesZeroWhenVal...
Still “Cheating”?<br />11 November 2009<br />© Rob Myers 2009<br />44<br />class CurrencyConverter {<br />    public doubl...
Maintain the Tests<br />11 November 2009<br />© Rob Myers 2009<br />45<br />[TestMethod]<br />public void GivesZeroWhenVal...
TestInitialize Runs Before Each Test<br />11 November 2009<br />© Rob Myers 2009<br />46<br />private CurrencyConverter co...
What is the Expected Answer?<br />11 November 2009<br />© Rob Myers 2009<br />47<br />[TestMethod]<br />public void Conver...
Let’s “Guess”…<br />11 November 2009<br />© Rob Myers 2009<br />48<br />[TestMethod]<br />public void ConvertsDollarsToEur...
…Get it Working…<br />11 November 2009<br />© Rob Myers 2009<br />49<br />public double convert(<br />    double value, st...
…Refactor…<br />11 November 2009<br />© Rob Myers 2009<br />50<br />public double convert(<br />    double value, string f...
…And Make a Note of It<br />To Do<br /><ul><li>When currencies are the same.
When value is zero.
Fix the hard-coded ConversionRate</li></ul>11 November 2009<br />© Rob Myers 2009<br />51<br />
11 November 2009<br />© Rob Myers 2009<br />52<br />Well, What is It???<br />Where does it come from?<br />
Circumstantial Coupling?<br />11 November 2009<br />© Rob Myers 2009<br />53<br />CurrencyConverter<br />
Managing the Transaction<br />11 November 2009<br />© Rob Myers 2009<br />54<br />Account<br />CurrencyConverter<br />Hold...
Another Object Emerges<br />To Do<br /><ul><li>When currencies are the same.
When value is zero.
Fix hard-coded ConversionRate().
Write ConversionRates.
Make a factory for ConversionRates that uses the FOREX.com Web Service.</li></ul>11 November 2009<br />© Rob Myers 2009<br...
New Test Class<br />11 November 2009<br />© Rob Myers 2009<br />56<br />using Microsoft.VisualStudio.TestTools.UnitTesting...
Fail<br />11 November 2009<br />© Rob Myers 2009<br />57<br />public class ConversionRates {<br />    public void PutRate(...
No Need to be Coy<br />11 November 2009<br />© Rob Myers 2009<br />58<br />public class ConversionRates {<br />    private...
Isolate Behavior<br />11 November 2009<br />© Rob Myers 2009<br />59<br />public class ConversionRates {<br />    private ...
Next?<br />To Do<br /><ul><li>When currencies are the same.
When value is zero.
Upcoming SlideShare
Loading in …5
×

Test-Driven Development Overview

1,067 views

Published on

An overview of test-driven development including a brief scripted demo.

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

  • Be the first to like this

No Downloads
Views
Total views
1,067
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • NW story: Can’t do TDD, they haven’t even figured out unit tests yet!
  • TDD is easier.My personal goal is to show you Robbie’s point of view. Perhaps you’ll make it your own.
  • Codified by Kent Beck.From his XP practices.Led to automated unit-test frameworks and refactoring tools.Adapted by Agilists into two distinct practices.
  • Problem:Time spent RE-testingTime spent debugging
  • SolutionFastRepeatable resultsBetter than…
  • Story 15 years old, at least (Phoenix).Truck stuck.Fire dept and others arrive and try to figure out what to do.Anecdotally, a young man walks up and says “Why not deflate the tires?”Developers can think about a problem and come up with a possible solution.BUT…first specify the question (Jeopardy-style)
  • We’re talking about a single coding event (story?) and it’s test. If the coding cycle is months, then the delay could be months.The developer will have forgotten. The BA/PO may have forgotten, too!<done with anim and closing gap> Where do we gain value from testing? Running the test, or writing it?
  • If you have to think about how you’d interact with the product, what are you doing? [Analysis]This is the final detailed analysis of a story before AND WHILE it’s being implemented. JIT Analysis!
  • Reduces defects now: Tells you when a task is done, and done correctly.Reduces defects later: Comprehensive suite of isolated regression tests detect and isolate failures immediately.Much less time troubleshooting/debugging and re-testing.For developersBugs are easier and faster to fix while they’re freshBugs are found and fixed before other dependent code is writtenFewer returns from QA, more time spent on developing not fixingFor TestersSpend more time on more critical testing (not finding and validating defects)For the Whole TeamDaily measurable progressProduct health and flexibilitySanity in the workplace and enjoyable work
  • Problem: Iterations imply incremental developmentChange can result in a negative feedback loop - ENTROPY: The Agilist’s DilemmaWe have to address this. It’s not easy, until it becomes easy. At first, we’d rather not check the oil…
  • Problem: Dependencies
  • Solution:… Actors
  • One Analogy for the DesignThe suite of tests preserves all prior behavior while we address design, allowing for Emergent Designs
  • AnAnalogy for theProgrammer:Each test remains as an individual investment in the behavior and the quality of the design
  • Does TDD Work?Microsoft and IBM…Also, “approximately 40% fewer defects” Laurie Williams for ACMdefect rate is considerably lowerfuture enhancements easierin a dynamic market. defects quickly detected
  • Weinberg’s “Are Your Lights On?” Golden ______OTIS2 data conversionOTIS2 “GUI” conversionDenali Internationalization
  • Roadblocks to AdoptionDevelopers skip refactoring, don’t spend the minute to look for and clean up a new bit of code duplication.Inexperienced coaches who confuse the developer-style TDD with the team ATDDManagers waffling over the use of TDD, which limits its effectiveness…and others.
  • A habit…We still use when times are tough…Because we know there is a long-term benefit.Habit: 30-days, support-groupBenefits org, team, individualDiscipline prevents regret (debt).
  • We thought about “Deposit” except that’s not what it is once it’s been deposited<click>And we’re going to tackle Holding first
  • Holding has a useful interface so it may convert its value to different currency, but… the conversion doesn’t really belong in Holding, does it? My gut is telling me it will be helpful to isolate it, keep it simpleIf we guess wrong? Refactor away CurrencyConverter. RARE REFACTORING!
  • Read it<click>tolerance<click> won’t compile, of course
  • VS writes this. Nice, in case we ever forget, but I want the test to FAIL, not THROW.
  • Is this crazy?
  • If it’s a constant, make it a constantOr find a simplistic implementation
  • If there’s no clear refactoring, go on to the next test.
  • Rodin’s chipping away whatever didn’t look like a seated manTriangulation *IS* Test-First<click>Don’t add more production BEHAVIOR without a failing test.
  • This is a perfectly good design for what we’ve asked the system to do so far.As long as the design does not start to DEGRADE!
  • It’s not really about reduction of duplication, but about arranging for all tests in the class.One test class per behavior group.
  • What if we don’t know?Find out, or make it happen.
  • Why? To isolate the problem.Note that we’re thinking about parameter lists. “Programming by intention”. If we miss one, we can refactor further, later.
  • Should the converter know?
  • We’re deferring the decision.<TODO: Maybe draw a sequence diagram!>
  • Part of Emergent Design: Discovering that YOU need something, and building it.
  • Refactor? Is there duplication?
  • If you doubt yourself, just change one of the 50’s.Now there’s duplication in the test. Make a constant <TODO: do it!>
  • We’re not actually going to do it, but what might it look like?
  • We could do these.Or we could, as a team, test that they are impossible.What benefit in NOT doing these? [Simplicity, else each object has to be defensive, as though it were being exposed to “other programmers”]
  • Which I will leave for the enthusiastic TDD programmer to complete (it ain’t hard)
  • Thank you!
  • Test-Driven Development Overview

    1. 1. Realistic Test-Driven Development:Paying and PreventingTechnical Debt<br />Rob Myers<br />Agile Development Practices<br />11 November 2009<br />11 November 2009<br />© Rob Myers 2009<br />1<br />
    2. 2. 11 November 2009<br />© Rob Myers 2009<br />2<br />Unit testing is sooooDEPRESSING<br />
    3. 3. 11 November 2009<br />© Rob Myers 2009<br />3<br />TDD is fun,<br />and provides much more than just unit-tests!<br />
    4. 4. 11 November 2009<br />© Rob Myers 2009<br />4<br />from<br />XP<br />to<br />ATDD<br />&<br />BDD<br />
    5. 5. 11 November 2009<br />© Rob Myers 2009<br />5<br />waste<br />
    6. 6. 11 November 2009<br />© Rob Myers 2009<br />6<br />#1<br />automation<br />public static void Main() {<br />Console.WriteLine(<br /> “I sure hope this works...” +<br />myObject.Foo());<br />}<br />
    7. 7. 11 November 2009<br />© Rob Myers 2009<br />7<br />
    8. 8. 11 November 2009<br />© Rob Myers 2009<br />8<br />#2<br />Test-First<br />We write a test before writing the code that makes it pass.<br />
    9. 9. Why Wait?<br />11 November 2009<br />© Rob Myers 2009<br />9<br />Code<br />Test<br />Months<br />Code<br />Test<br />Weeks<br />Code<br />Test<br />Days<br />Code<br />Test<br />
    10. 10. What If?<br />11 November 2009<br />© Rob Myers 2009<br />10<br />Code<br />Run Test<br />Test<br />Write Test<br />Run Test<br />Run Test<br />Run Test<br />
    11. 11. Benefits of Test-First<br />Just-In-Time analysis.<br />We know when something is…<br />…done.<br />…done correctly.<br />…broken.<br />…and fixed!<br />11 November 2009<br />© Rob Myers 2009<br />11<br />
    12. 12. 11 November 2009<br />© Rob Myers 2009<br />12<br />
    13. 13. 11 November 2009<br />© Rob Myers 2009<br />13<br />#3<br />Any behavior-preserving change that improves maintainability.<br />
    14. 14. 11 November 2009<br />© Rob Myers 2009<br />14<br />
    15. 15. 11 November 2009<br />© Rob Myers 2009<br />15<br />
    16. 16. 11 November 2009<br />© Rob Myers 2009<br />16<br />#4<br />Mock Objects<br />
    17. 17. Prep road-data for new Mars Colony Road/Canal Service<br /><ul><li> Build ‘Earth’ adapter around map-data service
    18. 18. Refactor all callers to use Earth (all?)
    19. 19. Extract abstract parent ‘Planet’
    20. 20. Planet needs a factory
    21. 21. Test that Mars adapter calls new Mars-map service (mock the service)
    22. 22. Test that Planet factory determines which planet client is on (mock config file)</li></ul>11 November 2009<br />© Rob Myers 2009<br />17<br />#5<br />A To-Do List<br />
    23. 23. 11 November 2009<br />© Rob Myers 2009<br />18<br />Analogies & Metaphors<br />
    24. 24. 11 November 2009<br />© Rob Myers 2009<br />19<br />
    25. 25. 11 November 2009<br />© Rob Myers 2009<br />20<br />
    26. 26. 11 November 2009<br />© Rob Myers 2009<br />21<br />“The results of the case studies indicate that the pre-release defect density of the four products decreased between 40% and 90% relative to similar projects that did not use the TDD practice. Subjectively, the teams experienced a 15–35% increase in initial development time after adopting TDD.”<br />http://research.microsoft.com/en-us/projects/esm/nagappan_tdd.pdf, Nagappan et al, © Springer Science + Business Media, LLC 2008<br />
    27. 27. 11 November 2009<br />© Rob Myers 2009<br />22<br />real value<br />
    28. 28. 11 November 2009<br />© Rob Myers 2009<br />23<br />architectural<br />perspective<br />
    29. 29. 11 November 2009<br />© Rob Myers 2009<br />24<br />roadblocks<br />
    30. 30. 11 November 2009<br />© Rob Myers 2009<br />25<br />discipline<br />
    31. 31. 11 November 2009<br />© Rob Myers 2009<br />26<br />steps<br />Write oneunit test.<br />Build or add to the object under test until everything compiles.<br />Red: Watch the test fail!<br />Green: Make all the tests pass by changing the object under test.<br />Clean: Refactormercilessly!<br />Repeat.<br />
    32. 32. 11 November 2009<br />© Rob Myers 2009<br />27<br /> given<br /> when<br /> then<br />
    33. 33. 11 November 2009<br />© Rob Myers 2009<br />28<br />TDD Demo<br />
    34. 34. 11 November 2009<br />© Rob Myers 2009<br />29<br />Basic UML Class Diagrams<br />Foo<br />- intprivateVariable<br />+ intPublicMethod()<br />Bar<br />Baz<br />+ void AbstractMethod(<br /> object parameter)<br />- void PrivateMethod()<br />
    35. 35. 11 November 2009<br />© Rob Myers 2009<br />30<br />Global Currency Money-Market Account<br />
    36. 36. 11 November 2009<br />© Rob Myers 2009<br />31<br />Global ATMAccess<br />
    37. 37. Stories<br />As Rob the US account holder, I want to be able to withdraw USD from a US ATM, but select which currency holdings to withdraw from.<br />As Rob, traveling in Europe, I want to be able to withdraw EUR from either my EUR holdings or my USD holdings. The default should be the most beneficial to me at the time.<br />Shortly after the end of each month, I want to receive a report of my holdings and balance. The total balance should appear in the currency of my account address (USD).<br />11 November 2009<br />© Rob Myers 2009<br />32<br />
    38. 38. Primary Objects<br />11 November 2009<br />© Rob Myers 2009<br />33<br />Currency<br />Account<br />Holding<br />
    39. 39. More Detail<br />11 November 2009<br />© Rob Myers 2009<br />34<br />Currency<br />Holding<br />value<br />currency<br />currencyConverter<br />CurrencyConverter<br />convert value to<br /> another currency<br />
    40. 40. Start Simple<br />To Do<br /><ul><li>When currencies are the same.
    41. 41. When value is zero.</li></ul>11 November 2009<br />© Rob Myers 2009<br />35<br />
    42. 42. Specification, and Interface<br />11 November 2009<br />© Rob Myers 2009<br />36<br />[TestMethod]<br />public void GivesSameValueWhenSameCurrencyRequested() {<br />CurrencyConverter converter = new CurrencyConverter();<br /> string sameCurrency = &quot;USD&quot;;<br /> double sameValue = 100.0000;<br /> double converted = converter.convert(<br />sameValue, sameCurrency, sameCurrency);<br />Assert.AreEqual(sameValue, converted, 0.00004);<br />}<br />Will not compile. <br />
    43. 43. “Thank You, But…”<br />11 November 2009<br />© Rob Myers 2009<br />37<br />using System;<br />class CurrencyConverter {<br /> public double convert(<br /> double value, string from, string to) {<br /> throw new NotImplementedException();<br /> }<br />}<br />
    44. 44. “…I Want to See it Fail Successfully”<br />11 November 2009<br />© Rob Myers 2009<br />38<br />class CurrencyConverter {<br /> public double convert(<br /> double value, string from, string to) {<br />return 0.0;<br /> }<br />}<br />
    45. 45. Just Enough to Pass<br />11 November 2009<br />© Rob Myers 2009<br />39<br />public double convert(<br /> double value, string from, string to) {<br /> return 100.0;<br />}<br />
    46. 46. a. Refactor Away the Duplication<br />11 November 2009<br />© Rob Myers 2009<br />40<br />[TestMethod]<br />public void GivesSameValueWhenSameCurrencyRequested() {<br />CurrencyConverter converter = new CurrencyConverter();<br /> string sameCurrency = &quot;USD&quot;;<br /> double sameValue = 100.0000;<br /> double converted = converter.convert(<br />sameValue, sameCurrency, sameCurrency);<br />Assert.AreEqual(sameValue, converted, 0.00004);<br />}<br />public double convert(<br /> double value, string from, string to) {<br /> return 100.0;<br />}<br />
    47. 47. b. Triangulate<br />11 November 2009<br />© Rob Myers 2009<br />41<br />
    48. 48. 11 November 2009<br />© Rob Myers 2009<br />42<br />We don’t add any behavior without a failing test…<br />Rodin’s The Thinker, photo by CJ on Wikipedia<br />
    49. 49. Triangulating Test<br />11 November 2009<br />© Rob Myers 2009<br />43<br />[TestMethod]<br />public void GivesZeroWhenValueIsZero() {<br />CurrencyConverter converter = new CurrencyConverter();<br /> double zero = 0.0000;<br /> double converted = converter.convert(<br /> zero, &quot;USD&quot;, &quot;EUR&quot;);<br />Assert.AreEqual(zero, converted, 0.00004);<br />}<br />
    50. 50. Still “Cheating”?<br />11 November 2009<br />© Rob Myers 2009<br />44<br />class CurrencyConverter {<br /> public double convert(<br /> double value, string from, string to) {<br /> return value;<br /> }<br />}<br />
    51. 51. Maintain the Tests<br />11 November 2009<br />© Rob Myers 2009<br />45<br />[TestMethod]<br />public void GivesZeroWhenValueIsZero() {<br />CurrencyConverter converter = new CurrencyConverter();<br /> // ...<br />}<br />[TestMethod]<br />public void GivesSameValueWhenSameCurrencyRequested() {<br />CurrencyConverter converter = new CurrencyConverter();<br /> // ...<br />}<br />
    52. 52. TestInitialize Runs Before Each Test<br />11 November 2009<br />© Rob Myers 2009<br />46<br />private CurrencyConverter converter;<br />[TestInitialize]<br />public void InitConverter() {<br /> converter = new CurrencyConverter();<br />}<br />[TestMethod]<br />public void GivesZeroWhenValueIsZero() {<br /> // ...<br />}<br />[TestMethod]<br />public void GivesSameValueWhenSameCurrencyRequested() {<br /> // ...<br />}<br />
    53. 53. What is the Expected Answer?<br />11 November 2009<br />© Rob Myers 2009<br />47<br />[TestMethod]<br />public void ConvertsDollarsToEuros() {<br /> double converted = converter.convert(<br /> 100.0000, &quot;USD&quot;, &quot;EUR&quot;);<br />Assert.AreEqual(???, converted, 0.00004);<br />}<br />
    54. 54. Let’s “Guess”…<br />11 November 2009<br />© Rob Myers 2009<br />48<br />[TestMethod]<br />public void ConvertsDollarsToEuros() {<br /> double converted = converter.convert(<br /> 100.0000, &quot;USD&quot;, &quot;EUR&quot;);<br />Assert.AreEqual(50.0000, converted, 0.00004);<br />}<br />
    55. 55. …Get it Working…<br />11 November 2009<br />© Rob Myers 2009<br />49<br />public double convert(<br /> double value, string from, string to) {<br /> if (to.Equals(from))<br /> return value;<br /> return value * 0.5000;<br />}<br />
    56. 56. …Refactor…<br />11 November 2009<br />© Rob Myers 2009<br />50<br />public double convert(<br /> double value, string from, string to) {<br /> if (to.Equals(from))<br /> return value;<br /> return value * ConversionRate(from, to);<br />}<br />private double ConversionRate(string from, string to) {<br /> return 0.5000;<br />}<br />
    57. 57. …And Make a Note of It<br />To Do<br /><ul><li>When currencies are the same.
    58. 58. When value is zero.
    59. 59. Fix the hard-coded ConversionRate</li></ul>11 November 2009<br />© Rob Myers 2009<br />51<br />
    60. 60. 11 November 2009<br />© Rob Myers 2009<br />52<br />Well, What is It???<br />Where does it come from?<br />
    61. 61. Circumstantial Coupling?<br />11 November 2009<br />© Rob Myers 2009<br />53<br />CurrencyConverter<br />
    62. 62. Managing the Transaction<br />11 November 2009<br />© Rob Myers 2009<br />54<br />Account<br />CurrencyConverter<br />Holding<br />Holding<br />Holding<br />ConversionRates<br />Holding<br />
    63. 63. Another Object Emerges<br />To Do<br /><ul><li>When currencies are the same.
    64. 64. When value is zero.
    65. 65. Fix hard-coded ConversionRate().
    66. 66. Write ConversionRates.
    67. 67. Make a factory for ConversionRates that uses the FOREX.com Web Service.</li></ul>11 November 2009<br />© Rob Myers 2009<br />55<br />
    68. 68. New Test Class<br />11 November 2009<br />© Rob Myers 2009<br />56<br />using Microsoft.VisualStudio.TestTools.UnitTesting;<br />[TestClass]<br />public class ConversionRatesTests {<br /> [TestMethod]<br /> public void StoresAndRetrievesRates() {<br />ConversionRates rates = new ConversionRates();<br /> string from = &quot;USD&quot;;<br /> string to = &quot;EUR&quot;;<br /> double rate = 0.7424;<br />rates.PutRate(from, to, rate);<br />Assert.AreEqual(rate, rates.GetRate(from, to));<br /> }<br />}<br />
    69. 69. Fail<br />11 November 2009<br />© Rob Myers 2009<br />57<br />public class ConversionRates {<br /> public void PutRate(string from, string to, double rate) {<br /> }<br /> public double GetRate(string from, string to) {<br /> return 0.0;<br /> }<br />}<br />
    70. 70. No Need to be Coy<br />11 November 2009<br />© Rob Myers 2009<br />58<br />public class ConversionRates {<br /> private Dictionary&lt;string, double&gt; rates<br /> = new Dictionary&lt;string, double&gt;();<br /> public void PutRate(string from, string to, double rate) {<br /> rates[from + to] = rate;<br /> }<br /> public double GetRate(string from, string to) {<br /> return rates[from + to];<br /> }<br />}<br />
    71. 71. Isolate Behavior<br />11 November 2009<br />© Rob Myers 2009<br />59<br />public class ConversionRates {<br /> private Dictionary&lt;string, double&gt; rates<br /> = new Dictionary&lt;string, double&gt;();<br /> public void PutRate(string from, string to, double rate) {<br /> rates[Key(from, to)] = rate;<br /> }<br /> public double GetRate(string from, string to) {<br /> return rates[Key(from, to)];<br /> }<br /> private string Key(string from, string to) {<br /> return from + to;<br /> }<br />}<br />
    72. 72. Next?<br />To Do<br /><ul><li>When currencies are the same.
    73. 73. When value is zero.
    74. 74. Fix hard-coded ConversionRate().
    75. 75. Write ConversionRates.
    76. 76. Make a factory for ConversionRates that uses the FOREX.com Web Service.</li></ul>11 November 2009<br />© Rob Myers 2009<br />60<br />
    77. 77. Fix SetUp<br />11 November 2009<br />© Rob Myers 2009<br />61<br />[TestClass]<br />public class CurrencyConverterTests {<br /> private CurrencyConverter converter;<br /> [TestInitialize]<br /> public void InitConverter() {<br />ConversionRates rates = new ConversionRates();<br />rates.PutRate(&quot;USD&quot;, &quot;EUR&quot;, 0.5000);<br /> converter = new CurrencyConverter(rates);<br /> }<br />
    78. 78. Partially Refactored…<br />11 November 2009<br />© Rob Myers 2009<br />62<br />public class CurrencyConverter {<br /> private ConversionRates rates;<br /> public CurrencyConverter(ConversionRates rates) {<br />this.rates = rates;<br /> }<br /> private double ConversionRate(string from, string to) {<br /> return 0.5000;<br /> }<br />
    79. 79. Replace the Hard-Coded Value<br />11 November 2009<br />© Rob Myers 2009<br />63<br />public class CurrencyConverter {<br /> private ConversionRates rates;<br /> public CurrencyConverter(ConversionRates rates) {<br />this.rates = rates;<br /> }<br /> private double ConversionRate(string from, string to) {<br /> return rates.GetRate(from, to);<br /> }<br />
    80. 80. What Remains?<br />To Do<br /><ul><li>When currencies are the same.
    81. 81. When value is zero.
    82. 82. Fix hard-coded ConversionRate().
    83. 83. Write ConversionRates.
    84. 84. Make a factory for ConversionRates that uses the FOREX.com Web Service.</li></ul>11 November 2009<br />© Rob Myers 2009<br />64<br />
    85. 85. What is the Missing Piece?<br />11 November 2009<br />© Rob Myers 2009<br />65<br />ConversionRates rates =<br />ConversionRates.ByAccountAnd???(<br /> account, ???);<br />
    86. 86. What If, After a Break…<br />To Do<br /><ul><li>Make a ByAccountAndDate() factory for ConversionRates that uses the FOREX.com Web Service.
    87. 87. ConversionRates returns 1/rate if inverse rate found.
    88. 88. ConversionRates throws when rate not found.</li></ul>11 November 2009<br />© Rob Myers 2009<br />66<br />
    89. 89. Testing Exceptional Behavior<br />11 November 2009<br />© Rob Myers 2009<br />67<br />[TestMethod]<br />public void ThrowsExceptionIfRateNotFound() {<br />ConversionRates rates = new ConversionRates();<br /> string from = &quot;BAR&quot;;<br /> string to = &quot;BAZ&quot;;<br /> try {<br />rates.GetRate(from, to);<br />Assert.Fail(&quot;should throw&quot;);<br /> }<br /> catch (RateNotFoundException) {<br /> // expected<br /> }<br />}<br />
    90. 90. A New Exception<br />11 November 2009<br />© Rob Myers 2009<br />68<br />using System;<br />public class RateNotFoundException : Exception {<br />}<br />
    91. 91. 11 November 2009<br />© Rob Myers 2009<br />69<br />
    92. 92. Back in ConversionRates<br />11 November 2009<br />© Rob Myers 2009<br />70<br />public double GetRate(string from, string to) {<br /> if (!rates.ContainsKey(Key(from, to)))<br /> throw new RateNotFoundException();<br /> return rates[Key(from, to)];<br /> }<br />
    93. 93. An Alternative Test<br />11 November 2009<br />© Rob Myers 2009<br />71<br />[TestMethod,ExpectedException(typeof(RateNotFoundException))]<br />public void ThrowsExceptionIfRateNotFoundII() {<br />ConversionRates rates = new ConversionRates();<br /> string from = &quot;BAR&quot;;<br /> string to = &quot;BAZ&quot;;<br />rates.GetRate(from, to);<br />}<br />
    94. 94. An Expressive Testfor an Expressive Exception<br />11 November 2009<br />© Rob Myers 2009<br />72<br />[TestMethod]<br />public void ThrowsExceptionIfRateNotFound() {<br />ConversionRates rates = new ConversionRates();<br /> string from = &quot;BAR&quot;;<br /> string to = &quot;BAZ&quot;;<br /> try {<br />rates.GetRate(from, to);<br />Assert.Fail(&quot;should throw &quot;<br />+ typeof(RateNotFoundException).Name);<br /> }<br /> catch (RateNotFoundExceptione) {<br />StringAssert.Contains(e.Message, from);<br />StringAssert.Contains(e.Message, to);<br /> }<br />}<br />
    95. 95. 11 November 2009<br />© Rob Myers 2009<br />73<br />Test-Driven Development: By Example Kent Beck<br />Addison-Wesley, November 2002<br />Refactoring:<br />Improving the Design of Existing Code Martin FowlerAddison-Wesley, July 1999<br />The Art of Agile Development James Shore & Shane Warden O&apos;Reilly Media, October 2007<br /> Rob.Myers@agileInstitute.com<br />http://PowersOfTwo.agileInstitute.com/<br />

    ×