The Beauty of TDD

How you can use Test Driven Development to make things better

TDD

  • Write the Test
  • Make it Pass
  • Refactor

Red Green Refactor

contain

Why TDD?

  • Testable from the start
  • Tight feedback loop
  • Specific errors
  • Drives smaller, less coupled classes
  • Defines and Documents behavior
  • Creates an ongoing safety net
  • Provides a defense against regression
  • Refactor with peace of mind
  • Grows naturally more modular, flexible code
  • Intuitive way to break up large problems

Pencil Durability - A Kata

As a writer I want to be able use a pencil to write text on a sheet of paper so that I can better remember my thoughts


When the pencil is instructed to write a string of text on a sheet of paper, the paper should reflect the text that was written.


Text written by the pencil should always be appended to existing text on the paper. Thus, given a piece of paper with the text "She sells sea shells", when a pencil is instructed to write " down by the sea shore" on the paper, the paper will then contain the entire string (i.e. "She sells sea shells down by the sea shore").

Paper Returns Text

@Test
public void paperReturnsText() {
   Pencil pencil = new Pencil();
   String input = "She sells sea shells";

   Paper paper = new Paper();
   pencil.write(input, paper);

   Assert.assertEquals(input, paper.getPage());
}

Paper Returns Text

public class Pencil {

   public void write(String text, Paper paper) {

   }
}

Paper Returns Text

public class Paper {

   public String getPage() {
       return "She sells sea shells";
   }
}

contain

The Smallest Step

The Smallest Step

The Smallest Step

  • Be Lazy!
  • Be Simple
  • Be Dumb (not clever)

What did we test?

  • Created Paper Class
  • Created Pencil Class
  • Created an interface to write with a pencil
  • Created an interface to get a page’s text

What do we test next?

  • Smallest possible step
  • Provide value
  • Drive towards our story
  • Let’s not hardcode that string

Paper Returns Text

@Test
public void paperReturnsText() {
   Pencil pencil = new Pencil();
   String input = "She sells sea shells";

   Paper paper = new Paper();
   pencil.write(input, paper);

   Assert.assertEquals(input, paper.getPage());
}

Pencil Writes Text

@Test
public void pencilWritesTextToPaper() {
   Pencil pencil = new Pencil();
   String input = "Down by the sea shore";

   Paper paper = new Paper();
   pencil.write(input, paper);

   Assert.assertEquals(input, paper.getPage());
}

Pencil Writes Text

public class Paper {
   private String text = "";

   public String getPage() {
       return text;
   }

   public void setText(String text) {
       this.text = text;
   }
}

Pencil Writes Text

public class Pencil {

   public void write(String text, Paper paper) {
           paper.setText(text);
   }
}

What did we test?

  • Create an additional test (prevent hardcoding)
  • Enforce how pencil interacts with paper
  • Store text on paper

Pencil Durability - A Kata

As a writer I want to be able use a pencil to write text on a sheet of paper so that I can better remember my thoughts


When the pencil is instructed to write a string of text on a sheet of paper, the paper should reflect the text that was written.


Text written by the pencil should always be appended to existing text on the paper. Thus, given a piece of paper with the text "She sells sea shells", when a pencil is instructed to write " down by the sea shore" on the paper, the paper will then contain the entire string (i.e. "She sells sea shells down by the sea shore").

Pencil Appends Text

@Test
public void pencilAddsTextToPaper() {
   Pencil pencil = new Pencil();
   String first = "first part";
   String second = "second part";

   Paper paper = new Paper();
   pencil.write(first, paper);
   pencil.write(second, paper);

   Assert.assertEquals(first+second, paper.getPage());
}

Pencil Writes Text

public class Pencil {

   public void write(String text, Paper paper) {
           paper.setText(text);
   }
}

Pencil Appends Text

public class Paper {
   private String text = "";

   public String getPage() {
       return text;
   }

   public void setText(String text) {
       this.text += text;
   }
}

Pencil Appends Text

public class Paper {
   private String text = "";

   public String getPage() {
       return text;
   }

   public void setText(String text) {
       this.text += text;
   }
}

contain

What did we test?

  • Appending text
  • setText or addText?

Refactoring with Tests

public class Paper {
   private String text = "";

   public String getPage() {
       return text;
   }

   public void addText(String text) {
       this.text += text;
   }
}

Refactoring with Tests

public class Pencil {

   public void write(String text, Paper paper) {
           paper.addText(text);
   }
}

Pencil Durability - A Kata

As a writer I want to be able use a pencil to write text on a sheet of paper so that I can better remember my thoughts


When the pencil is instructed to write a string of text on a sheet of paper, the paper should reflect the text that was written.


Text written by the pencil should always be appended to existing text on the paper. Thus, given a piece of paper with the text "She sells sea shells", when a pencil is instructed to write " down by the sea shore" on the paper, the paper will then contain the entire string (i.e. "She sells sea shells down by the sea shore").

Refactoring the Tests Themselves

  • When is it appropriate to refactor tests?
  • Extract out common code
  • Make sure there is not shared state

Refactoring the Tests

@Test
public void paperReturnsText() {
   Pencil pencil = new Pencil();
   String input = "She sell sea shells";

   Paper paper = new Paper();
   pencil.write(input, paper);

   Assert.assertEquals(input, paper.getPage());
}

@Test
public void pencilWritesTextToPaper() {
   Pencil pencil = new Pencil();
   String input = "Down by the sea shore";

   Paper paper = new Paper();
   pencil.write(input, paper);

   Assert.assertEquals(input, paper.getPage());
}

Refactoring the Tests

@Test
public void pencilAddsTextToPaper() {
   Pencil pencil = new Pencil();
   String first = "first part";
   String second = "second part";

   Paper paper = new Paper();
   pencil.write(first, paper);
   pencil.write(second, paper);

   Assert.assertEquals(first+second, paper.getPage());
}

Refactoring the Tests

public class WriteOnPaperTest {
   private Pencil pencil;
   private Paper paper;

   @Before
   public void setup(){
       pencil = new Pencil();
       paper = new Paper();
   }

Refactoring the Tests

@Test
public void paperReturnsText() {
   Pencil pencil = new Pencil();
   String input = "She sell sea shells";

   Paper paper = new Paper();
   pencil.write(input, paper);

   Assert.assertEquals(input, paper.getPage());
}

The Focus of TDD

  • Not worried about code coverage
  • Not testing functions, testing features
  • Break large problems into small steps
  • Can we make a smaller slice? A smaller test?
  • How can we make a problem testable from the start?

Real Life

  • In a Kata, over-exaggerate
  • Production is not always ideal
  • It’s very easy to not TDD one thing, and suddenly not be TDDing anything

Cheating

  • Worst case scenario
  • Code or pseudocode a solution
  • Comment it out
  • Do it again, but this time with TDD
  • Make sure you understand the risks / dangers of this
  • Make sure the second time you’re really driving the code with tests

Level of detail

  • Refactoring without breaking all the tests
  • Testing implementation vs interface
  • Unit vs Integration

Review

  • TDD helps us build more stable code
  • Red Green Refactor
  • Katas help us practice
  • Be dumb, not clever
  • Writing text to a paper, small steps
  • Iterate everything (code and tests)
  • Focus on the right things
  • Strive for the right level of detail
  • Play!

Try the Kata yourself!

contain

Feedback

  • Please take a minute to fill out some feedback!