This is a presentation I have given that provides an overview of TDD and why it is important. It's free for download an use, please attribute the work though. The original PPT has some animation that makes parts of it easier to understand. Thanks!
2. Develop
Traditional Testing Test Scripts
Approach
Error Found!
Requirements
Execute
& Test Scripts
Design Specs
Test Expectation
≠
Executable Implementation
Develop Code,
Compile Executable
3. WTF
We’re supposed to be releasing
next week and you tell me this
isn’t working? Get that bug fixed!
4. The objective is
to kill bugs quickly,
but to
AVOID
them altogether!
5. What if…
Requirements Specs = Test Specs = Acceptance Criteria
Greater Detail
We built the right thing.
Design Specs = Test Specs = Quality Criteria
We built the thing right.
6. 1968know our
How do we
programs are correct?
1) Construct a proof showing what the
program should do
2) Develop code that
meets the proof
REPEAT until done
“A Constructive Approach
To the Problem of Program Correctness”, 1968, Edsger Wybe Dijkstra
7. In 1968,
in fact not until the late 90s,
the tools
didn’t exist
to implement Dr. Dijkstra’s vision.
Today,
the Constructive Approach = Test Driven Development (TDD)
(Specs = Tests = Proofs)
9. Acceptance Tests Stories/Functions
Greater Detail
Mark as ready for test when completed; based on Product Owner priority
xUnit Tests Specific Detailed Methods/Functions
Test completed code
10. X Unit Tests
Execute Test Create Mock Data Write Code
Write
Test(s) to To to
Show Failure Show Passing Test(s) Pass Tests
Why? Why? Why?
Know test will show Know test will show Tests = Specs
fail pass (expected
results)
Recurse over this pattern!
11. What does an xUnit
Test look like?
Say you've got a method,
getName(String path)
that parses a file name from a file path.
You can write a JUnit test class to feed it a path
and ensure that the results are what you
expected.
Simple example from jGuru.com
12. import java.io.File;
import junit.framework.*;
import junit.extensions.*;
public class ThingTester extends TestCase
{
public ThingTester (String name)
{
super (name);
}
public static void main(String[] args)
{
junit.textui.TestRunner.run(ThingTester.class);
}
public void testGetName() throws Exception
{
File myFile = new File("c:xxxyyyzzz.txt");
assertEquals("zzz.txt", myFile.getName());
}
}
13. To exercise the test:
Compile & run ThingTester.
• Little Dot = Passing Test;
• Assertion Failure & Stack Trace = Failure & location
• Write test code BEFORE program code used to
make it pass.
No problems? Add more test cases.
Examples: long paths, files with spaces in the
name, etc.
Stop when you feel you have enough edge cases
covered.
14. Understand Your Test Coverage
Tests should cover all critical methods
Tests should cover all critical edge cases
Tests should cover all critical error detection
Goal ≠ 100% coverage, but
Goal = 100% passing for what is covered
16. Acceptance Tests
Write Test
Describe Describe Execute Test Create Feature
Desired Feature to To
Behavior Test Steps Show Failure Pass Test
Why? Why?
Know test will show Tests = Specs
fail Underneath…
…are Unit Tests
Recurse over this pattern!
17. What does an Acceptance Test1
look like?
Say you've got a feature you want to implement
to compute a factorial…
You can write a feature that is the proof of this
function or story (including edge cases)
You also implement “steps” that poke at the
implementation. As the implementation changes
the steps change, but it is less common for the
feature to change.
1aka Executable Specification
Example from tutorial at lettuce.it
18. computefactorial.feature
Feature: Compute factorial
In order to play with Lettuce
As beginners
We'll implement factorial
Scenario: Factorial of 0
Given I have the number 0
When I compute its factorial
Then I see the number 1
Business Users can get this!
19. computefactorialsteps.py
from lettuce import *
@step('I have the number (d+)')
def have_the_number(step, number):
world.number = int(number)
@step('I compute its factorial')
def compute_its_factorial(step):
world.number = factorial(world.number)
@step('I see the number (d+)')
def check_number(step, expected):
expected = int(expected)
assert world.number == expected,
"Got %d" % world.number
20. To exercise the test:
Run Feature (duh!)
Add more code to fix problems and re-run….
21. computefactorial.py
def factorial(number):
return 1
by definition, we know that the factorial of 0 is 1
So as a mock, we created a function that just returned 1
22. To exercise the test:
Re-run Feature (duh!)
Need more than one case of course, so let’s add more
test cases; i.e. feature scenarios
23. Feature: Compute factorial
In order to play with Lettuce
As beginners
We'll implement factorial
Scenario: Factorial of 0
Given I have the number 0
When I compute its factorial
Then I see the number 1
}
Scenario: Factorial of 1
Given I have the number 1
When I compute its factorial In this case my steps
Then I see the number 1 & asserts were
Scenario: Factorial of 2 OK, sometimes you
Given I have the number 2 have to create more
When I compute its factorial
Then I see the number 2
24. To exercise the test: Rerun Feature (duh!)
Change code to fix problems and re-run….
25. computefactorial.py
def factorial(number):
number = int(number)
if (number == 0) or (number == 1):
return 1
else:
return number
26. To exercise the test:
Rerun Feature (duh!)
Add a few more cases so we get realistic…
27. Feature: Compute factorial
In order to play with Lettuce
As beginners
We'll implement factorial
Scenario: Factorial of 0
…
Scenario: Factorial of 1
…
Scenario: Factorial of 2
…
}
Scenario: Factorial of 3
Given I have the number 3 Again my steps &
When I compute its factorial
Then I see the number 6 asserts were Ok this
time,
Scenario: Factorial of 4 sometimes you have
Given I have the number 4
When I compute its factorial to create more
Then I see the number 24
31. Acceptance Tests work best when:
• Driven off of methods (functions) or several functions
• Perform below the UI level
If needed, Acceptance Tests can:
• Be driven off of the UI (usually performs a little slower;
must be done this way for something like PowerBuilder)
• Can be done manually
The specification independent of the flow or implementation.
The steps that poke at underlying code may need modification
over time.
33. How often?
For unit tests…
Every time code (which includes a test) is changed… This is probably
multiple times a day and should be at a minimum daily.
For acceptance tests…
Whenever a test is completed and then the code is completed. The
test may be completed on Tuesday, then code that pokes at the test
will be completed as the skeletal object is completed say around
Wednesday, and then perhaps Friday is when all the code for that
poke is completed.
34. A Full Complement of Tests
Product Technical Interaction
Design Design Design
Test to Acceptance xUnit UI Finite, Repeatable,
Specification Tests Tests Tests Automated
Test to Exploratory Stress Usability Environmental,
Failure Testing Testing Testing Less Automated
Diagram concept from p.76, Leading Lean
Development, Mary & Tom Poppendieck, 2010
36. For More Info…
References (Books) Unit Test Harnesses
• Specification by Example by • JUnit (java)
Godjo Adzic • Jasmine (JavaScript)
• Clean Code by Robert Martin • FlexUnit (Flex)
• pyUnit (Python)
• Ship It! By Jared Richardson
• utPLSQL (PL/SQL)
and William Gwaltney
• JUnit in Action by Vincent BDD (Acceptance Testing)
Massol • JBehave (Java)
• Cucumber (Ruby)
• Lettuce (Python)
Google: UI Testing
Unit Testing <language of interest> • Selenium