A brief code snippet to verify that other codes behave as expected
Automatic, repeatable
Fast & deterministic
Code's test is the test, the test's test is the code
Don’t write a line of new code unless you first have a failing automated test
Eliminate duplication
Write a test…
Make it run…
Make it right…
You are not allowed to write any production code unless it is to make a failing unit test pass.
You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
Write a test for the next bit of functionality you want to add
Write the functional code until the test passes
Refactor both new and old code to make it well structured
Strictly follow TDD rules and do fast cycles
Don't forget refactoring
As delivery doesn't matter, focus on readable Clean Code
Test names and bodies must document the codebase
There is no need for external dependencies, mocking, creating UI, etc.
TDD RULZ
Coderetreat
TDD RULZ
Coderetreat
Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
Any live cell with more than three live neighbours dies, as if by overcrowding.
Any live cell with two or three live neighbours lives on to the next generation.
Any dead cell with exactly three live neighbours becomes a live cell.
Test cases against behaviour
Test naming
Include the method under testing
Add context, preconditions
Write what will happen, the expected behaviour
describe("Math", () => {
describe("#add", () => {
it("should return 3 if 1 and 2 are given", () => {
expect(add(1,2)).toEqual(3)
describe("Math", () => {
describe("#add", () => {
it("should return the sum of two numbers given", () => {
expect(add(0,1)).toEqual(1)
expect(add(1,2)).toEqual(3)Bad:
Better:
describe("Given the balance is 1.000 €", () => {
describe("When making a deposit of 100 €", () => {
it("Then I expect the balance to be 1.100 €", () => ...describe("Given an initial balance in the account", () => {
describe("When making a deposit", () => {
it("Should add the deposit to the balance", () => ...Bad:
Better:
TDD Ping-Pong
Behavior in test names
Bonus: infinite table
describe("#getSquareArea", () => {
it("should return the area of a square with the given edge length", () => {
const area = getSquareArea(3)
expect(area).toEqual(9)
})
})
function getSquareArea(edgeLength: Number): Number {
return edgeLength * edgeLength
}describe("#getSquareArea", () => {
it("should return the area of ...", () => {
expect(getSquareArea(3)).toEqual(9)
})
})
// Iteration 1
function getSquareArea(edgeLength: Number): Number {
return 9
}
// Iteration 2
function getSquareArea(edgeLength: Number): Number {
return 3 * 3
}
// Iteration 3
function getSquareArea(edgeLength: Number): Number {
return edgeLength * edgeLength
}
describe("#getSquareArea", () => {
it("should return the area of ...", () => {
expect(getSquareArea(0)).toEqual(0)
})
})
function getSquareArea(edgeLength: Number): Number {
return 0
}
describe("#getSquareArea", () => {
it("should return the area of ...", () => {
expect(getSquareArea(0)).toEqual(0)
expect(getSquareArea(1)).toEqual(1)
})
})
function getSquareArea(edgeLength: Number): Number {
return edgeLength
}
describe("#getSquareArea", () => {
it("should return the area of ...", () => {
expect(getSquareArea(0)).toEqual(0)
expect(getSquareArea(1)).toEqual(1)
expect(getSquareArea(2)).toEqual(4)
})
})
function getSquareArea(edgeLength: Number): Number {
return edgeLength * edgeLength
}
TDD Ping-Pong
Behavior in test names
Inifinite table
Baby Steps
Naming:
Use descriptive, unambigious names
Replace magic number with named constants
Functions
Small & do one thing
Descriptive name
No side effects
Don't use flag arguments, create separate functions
"A method of an object should only call
methods on objects that are directly related to it"
"A method of an object should only call
methods on objects that are directly related to it"
class Piston {
move() {}
}
class Engine {
constructor(this.piston: Piston) { this.piston = new Piston() }
getPiston(): Piston {
return this.piston;
}
}
class Car {
constructor(this.engine: Engine) { this.engine = new Engine() }
start() {
this.engine.getPiston().move();
}
}"A method of an object should only call
methods on objects that are directly related to it"
class Piston {
move() {}
}
class Engine {
constructor(this.piston: Piston) { this.piston = new Piston() }
start(): Piston {
return this.piston.move();
}
}
class Car {
constructor(this.engine: Engine) { this.engine = new Engine() }
start() {
this.engine.start();
}
}First 5 minutes planning!
Small functions (max 3 lines)
No primitives
Bonus: No loop (for/while)
-