• Save
TDD? Sure, but What About My Legacy Code?
Upcoming SlideShare
Loading in...5
×
 

TDD? Sure, but What About My Legacy Code?

on

  • 1,736 views

 

Statistics

Views

Total Views
1,736
Views on SlideShare
1,725
Embed Views
11

Actions

Likes
0
Downloads
0
Comments
0

3 Embeds 11

http://www.linkedin.com 5
https://www.linkedin.com 5
http://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • We want to convert the old tin can into Why?
  • It’s a compromise for quality’s sake.Unless you buy TypeMock ($$$). There is a down-side to TypeMock: If you can test without improving your design, will you *ever*…???
  • Unplug the network!
  • This isn’t TDD. But you won’t be able to proceed with TDD without these techniques.If we find a bug, record it: In a bug tracker, or as a story.Not isolation. These are not “unit tests” - These tests can cover as much behavior as possible (though they must still be deterministic and pretty fast). And they don’t have to be pretty!Pinning tests should pass.The test is trying to “pin” behavior so we can refactor further.
  • What needs testing?
  • Very easyLean on the compiler
  • Production code!Can you test it?What good is it?
  • Varying dependency creation ORDuplicated dependency creation OR both.
  • Varying dependency creation ORDuplicated dependency creation OR both.
  • Creation has been separated from use. JUST A LITTLE, BUT ENOUGH.
  • What are we up to?
  • Alex Chaffee and WilliamPietre
  • Thank you!

TDD? Sure, but What About My Legacy Code? TDD? Sure, but What About My Legacy Code? Presentation Transcript

  • 14 July 2011
    © Agile Institute 2011
    1
    Café
    TDD?
    Sure, but What About My Legacy Code?
    Rob Myers
    for
    Test Driven Developers
    Bay Area
    14 Jul 2011
  • What is “Legacy Code”?
    14 July 2011
    © Agile Institute 2011
    2
  • 14 July 2011
    © Agile Institute 2011
    3
    “Code we’re afraid to change.”
    -- James Shore
    “Code without tests.”
    -- Michael Feathers
  • 14 July 2011
    © Agile Institute 2011
    4
  • Adding Tests Is Difficult
    14 July 2011
    © Agile Institute 2011
    5
    Circumstantial coupling: "I can’t test this without instantiating half the system!"
    Peculiar encapsulation: “I wish I could just test that private method!”
    Duplication:"I'll have to test this on all the subclasses!"
    Poor cohesion: "This MasterControlClass does everything, so the test will be enormous and complex!"
  • A Conundrum
    14 July 2011
    © Agile Institute 2011
    6
    We add tests to refactor safely.
    We have to refactor to add safe tests.
  • 14 July 2011
    © Agile Institute 2011
    7
    What could possibly go wrong?!
  • Choose Your Battles
    Test the code you need to change now (unless it is very difficult)
    Test the code that changes most often (even if it is difficult)
    Test the code that haunts your nightmares!
    14 July 2011
    © Agile Institute 2011
    8
  • Write “Pinning” Tests
    We don’t add or change behavior.
    We’re not bug-hunting.
    We aim for coverage.
    We must see GREEN.
    14 July 2011
    © Agile Institute 2011
    9
  • Technique: “The Three Questions”
    What behavior needs test coverage?
    What’s preventing us from writing a test?
    What can we do about that?
    14 July 2011
    © Agile Institute 2011
    10
  • Technique:Separate Behavior from Initialization
    It’s easier to test behavior when not coupled to initialization code.
    Use ‘Extract Method’ to preserve existing interfaces.
    14 July 2011
    © Agile Institute 2011
    11
  • Before
    14 July 2011
    © Agile Institute 2011
    12
    public void OpenOrderReport(
    OutputGadget output, string accountNumber) {
    Account account =
    LunExData.QueryAccount(accountNumber);
    Order[] openOrders =
    LunExData.QueryOrders(
    "open", accountNumber, DateTime.Now);
    foreach (Order order in openOrders) {
    // ...
    output.Write("Order #" + order.Number);
    // ...
    }
    }
  • After ‘Extract Method’
    14 July 2011
    © Agile Institute 2011
    13
    public void OpenOrderReport(
    OutputGadget output, string accountNumber) {
    Account account =
    LunExData.QueryAccount(accountNumber);
    Order[] openOrders =
    LunExData.QueryOrders(
    "open", accountNumber, DateTime.Now);
    FormatOpenOrderReport(output, account, openOrders);
    }
    private void FormatOpenOrderReport(
    OutputGadget output,
    Account account, Order[] openOrders) {
    foreach (Order order in openOrders) {
    // ...
    output.Write("Order #" + order.Number);
    // ...
  • Technique:Expose A Private Variable or Method
    Make a method public (at least accessible to tests)
    Wrap a variable in getter/setter methods.
    It may smell really bad.
    It will eventually be a useful addition to the interface, or will move to another object.
    14 July 2011
    © Agile Institute 2011
    14
  • Before
    14 July 2011
    © Agile Institute 2011
    15
    private void FormatOpenOrderReport(
    OutputGadget output,
    Account account, Order[] openOrders) {
    foreach (Order order in openOrders) {
    // ...
    output.Write("Order #" + order.Number);
    // ...
    }
    }
  • After
    14 July 2011
    © Agile Institute 2011
    16
    public void FormatOpenOrderReport(
    OutputGadget output,
    Account account, Order[] openOrders) {
    foreach (Order order in openOrders) {
    // ...
    output.Write("Order #" + order.Number);
    // ...
    }
    }
  • Technique:Wrap, Then Mock
    Add a simple delegating Proxy to…
    Code we cannot change.
    Final (Java) or sealed (.NET) classes.
    Classes with no accessible constructors.
    Anything with a broad (mostly-unused) interface.
    Feathers’s “Adapt Parameter” is an example of this.
    14 July 2011
    © Agile Institute 2011
    17
  • Delegating Proxy
    14 July 2011
    © Agile Institute 2011
    18
    ObjectUnderTest
    + MethodToTest()
    BrainlessProxy
    XYZZY
    + intFoo()
    + string Bar(int)
    + intFoo()
    + string Bar(int)
    + double Baz()
  • A New Production Class
    14 July 2011
    © Agile Institute 2011
    19
    public class BrainlessProxy {
    private XYZZY realOne;
    public BrainlessProxy(XYZZY theRealXYZZY) {
    this.realOne = theRealXYZZY;
    }
    public virtual intFoo() {
    return realOne.Foo();
    }
    public virtual string Bar(int parameter) {
    return realOne.Bar(parameter);
    }
    }
  • Tough Problem (Simple Example)
    14 July 2011
    © Agile Institute 2011
    20
    public class TrafficLight {
    public void SwitchLights() {
    Color newColor;
    if (currentColor.IsRed())
    newColor = new Green();
    else if (currentColor.IsGreen())
    newColor = new Yellow();
    else
    newColor = new Red();
    currentColor.Flash();
    Pause(3);
    currentColor.StopFlashing();
    newColor.LightUp();
    currentColor.Off();
    currentColor = newColor;
    }
  • Technique:Factory-Method Injection
    Extract a Factory Method for the dependency.
    Let the test create a “Testable” subclass of the Object Under Test.
    TestableFoo overrides the Factory Method and injects the mock.
    14 July 2011
    © Agile Institute 2011
    21
  • Before ‘Extract Method’
    14 July 2011
    © Agile Institute 2011
    22
    public void SwitchLights() {
    Color newColor;
    if (currentColor.IsRed())
    newColor = new Green();
    else if (currentColor.IsGreen())
    newColor = new Yellow();
    else
    newColor = new Red();
    currentColor.Flash();
    Pause(3);
    currentColor.StopFlashing();
    newColor.LightUp();
    currentColor.Off();
    currentColor = newColor;
    }
  • After ‘Extract Method’ part I
    14 July 2011
    © Agile Institute 2011
    23
    public void SwitchLights() {
    Color newColor;
    newColor = NextColor(currentColor);
    currentColor.Flash();
    Pause(3);
    currentColor.StopFlashing();
    newColor.LightUp();
    currentColor.Off();
    currentColor = newColor;
    }
  • After ‘Extract Method’ Part II
    14 July 2011
    © Agile Institute 2011
    24
    private Color NextColor(Color currentColor) {
    Color newColor;
    if (currentColor.IsRed())
    newColor = new Green();
    else if (currentColor.IsGreen())
    newColor = new Yellow();
    else
    newColor = new Red();
    return newColor;
    }
  • A Small Change
    14 July 2011
    © Agile Institute 2011
    25
    protected virtual Color NextColor(Color currentColor) {
    Color newColor;
    if (currentColor.IsRed())
    newColor = new Green();
    else if (currentColor.IsGreen())
    newColor = new Yellow();
    else
    newColor = new Red();
    return newColor;
    }
  • The Test, Part 1
    14 July 2011
    © Agile Institute 2011
    26
    public static MockColornewColor;
    [TestMethod]
    public void TrafficLightSwitchTurnsNextColorOn() {
    newColor = new MockColor();
    TrafficLighttrafficLight = new TestableTrafficLight();
    trafficLight.SwitchLights();
    Assert.IsTrue(newColor.WasTurnedOn());
    }
  • The Test, Part 2Override Just the Factory Method
    14 July 2011
    © Agile Institute 2011
    27
    public class TestableTrafficLight : TrafficLight {
    protected override Color NextColor(Color currentColor) {
    return newColor;
    }
    }
    public class MockColor : Color {
    bool wasLit = false;
    public override void LightUp() {
    wasLit = true;
    }
    public bool WasTurnedOn() {
    return wasLit;
    }
    }
  • When to Use a Factory Method
    “I don’t know, but…”
    If creation of the dependency is buried deep within conditional code.
    If the Factory Method is (or can be) used in multiple places.
    If Dependency Injection seems worse (e.g. at a published API).
    14 July 2011
    © Agile Institute 2011
    28
  • 14 July 2011
    © Agile Institute 2011
    29
  • 14 July 2011
    © Agile Institute 2011
    30
  • 14 July 2011
    © Agile Institute 2011
    31
    Rob.Myers@agileInstitute.com
    http://PowersOfTwo.agileInstitute.com/