Test-Driven

by Alex Chaffee

alexch @ gmail.com

Intended Audience

Part I: Basic Techniques

Red, Green, Refactor

Make it green, then make it clean

Make it green

Addicted to green

A Test In Three Acts

Assert

One Step At A Time

The Null Test

Test List

Fake it till you make it

Assert First

Fake It 'Til You Make It

Obvious Implementation

Interlude: The Blank Page

Part II: Testing Philosophy

Automated Testing Layers

A Good Test Is...

Tests are "Executable Specifications"

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." – Martin Fowler

Why do you test?

Why do you test?

When do you test?

When do you test?

When do you test?

Why test first?

Why test first? (cont.)

Can't I write tests later?

How can you write tests for code that doesn't exist?

"If you can't write a test, then you don't know what the code should do. And what business do you have writing code in the first place when you can't say what it's supposed to do?" - Rob Mee

Unit Testing Is Hard...

...but it makes your life easier

Test-Driving Is Slower At First

Test for "essential complexity"

Meszaros' Principles of Test Automation

Tests Are An Extension of Code

Part III: Advanced Techniques

What to test?

Test everything that could possibly break

How much to test?

Triangulate To Abstraction

Step one:

public void testSum() {
  assertEquals(4, plus(3,1));
}
int plus(int x, y) {
  return 4;
}

Step two:

public void testSum() {
  assertEquals(4, plus(3,1));
  assertEquals(5, plus(3,2));
}
int plus(int x, y) {
  return x + y;
}

Full Range Testing

Positive Tests

Negative Tests

Boundary Conditions

Descriptive Test Naming

BDD can help...

describe Set do
  context "when newly created" do
    subject { Set.new }
    it { should be_empty }
  end
end

Should Statements

Test-Only Methods

Refactoring Test Code

Refactoring Test Code - How?

Evident Data

Increase test readability by clarifying your input and output values

assertEquals(86400, new Day().getSeconds())

vs.

assertEquals(60 * 60 * 24, new Day().getSeconds())

vs.

secondsPerMinute = 60
minutesPerHour = 60
hoursPerDay = 24
assertEquals(secondsPerMinute * minutesPerHour * hoursPerDay,
  new Day().getSeconds())

Matrix Tests

Characterization Tests

Testing Exceptions

public void testUnknownCountry() {
  try {
    currencyConverter.getRate("Snozistan");
    fail("Should have thrown an exception for unknown country");
  } catch (UnknownCountryException e) {
    // ok
  }
}

Characterization Tests

Pair Programming

Ping-Pong Pairing

Regression Test

"Regression tests are tests that you would have written originally." - Kent Beck

Do Over

Leave One For Tomorrow

The Need For Speed

Continuous Integration

Retrofitting

Q: What to do when you have an existing untested codebase?

A: Start small!

Fixtures and Factories

Test Doubles (Mock Objects)

A Test Double replaces the "real" instance of an object used by the production code with something suitable for the currently running test, but with the same interface.

Test Doubles in general are often called Mock Objects, but there's also a specific technical type of double called a Mock.

Test Doubles

Test Doubles (cont.)

Mock Clock

A very useful test double

In ruby:

@fake_time = Time.now
Time.stub(:now) { @fake_time }

Complete Construction

BDD (specs)

Outside-in vs. Inside-out

Inside-out

Outside-in

Outside-in design, inside-out development

Part IV: Q&A

Thanks!

Next: Refactoring >>

Outline

[contents]

Test Driven Slides - Code Like This

/

#