SlideShare a Scribd company logo
TDD FOR THE WIN
Basics to Test Driven Development
May 2014 Minh Ngoc Dang
Senior Developer at ThoughtWorks
ThoughtWorks University Trainer
Minh Ngoc Dang
TESTING
WHY TESTING?
Lots of reasons! Here are a select few
Verify functionality of
application
Catch bugs and prevent them from
coming back
Serve as documentation for
maintainability purposes
BUT WHAT ABOUT…?
? How do we make sure we have full test coverage?
? How can we be confident all cases are covered?
? How can we prevent bugs from happening?
TDD!
TEST DRIVEN DEVELOPMENT!
BUT WAIT…WHAT IS IT?
BUT WAIT…WHAT IS IT?
TEST DRIVING MEANS
Writing tests before writing code
Write the minimum amount of code
necessary to make tests pass
Rinse and repeat
TESTS FIRST?! BUT
WHY?
WHY TDD?
Back to previously posed questions
Test
Coverage?
Cases Covered? Bug Prevention?
TEST COVERAGE
Tests written before code
TEST COVERAGE
Tests written before code
Ensure all code covered by tests
TEST COVERAGE
Tests written before code
Ensure all code covered by tests
High test coverage
WHY TDD?
Back to previously posed questions
Test
Coverage?
Cases Covered? Bug Prevention?
TEST CASES
Test cases reflect exactly what code
does
TEST CASES
Test cases reflect exactly what code
does
Visible list of functionality
TEST CASES
Test cases reflect exactly what code
does
Visible list of functionality
Easy to see which
cases are missing
WHY TDD?
Back to previously posed questions
Test
Coverage?
Cases Covered? Bug Prevention?
BUG PREVENTION
Mental shift in thinking up test case
before code
BUG PREVENTION
Mental shift in thinking up test case
before code
Encourage edge case testing
BUG PREVENTION
Mental shift in thinking up test case
before code
Encourage edge case testing
Help prevent bugs in
edge cases
WHY TDD?
Back to previously posed questions
Test
Coverage?
Cases Covered? Bug Prevention?
AND THAT’S NOT ALL!
TIME SAVER
Ease in debugging
Confidence in refactoring
DRIVING DESIGN
Help define usage – How should the
code be used?
Only write necessary code – YAGNI!
SO HOW CAN I TDD?
RED – GREEN - REFACTOR
New Test New Test New Test
Red
GreenRefactor
Red
GreenRefactor
Red
GreenRefactor
EXAMPLE
You are given strings of different lengths. If
the number of vowels are more than 30%
of the string length then insert ‘mommy’ for
each continuous set of vowels.
 his → hmommys
 hear → hmommyr
✗ hear → hmommymommyr
TEST CASES
“” → “” // empty string
“str” → “str” // no vowels
“a” → “mommy” // single vowel
“blah” → “blah” // < 30% length
“bla” → “blmommy” // > 30% length
“blaa” → “blmommy” // continuous vowels
“blaaha” → “blmommyhmommy”
// multi sets of vowels
“blA” → “blmommy” // capital letters
Null → raise exception // null checks
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {
String word = "";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("", mommifiedWord);
}
}
SOURCE
public class Mommifier {
public String mommify(String word) {
return null;
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {
String word = "";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("", mommifiedWord);
}
}
SOURCE
public class Mommifier {
public String mommify(String word) {
return "";
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {
String word = "";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("", mommifiedWord);
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {
String word = "str";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("str", mommifiedWord);
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {
String word = "str";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("str", mommifiedWord);
}
}
SOURCE
public class Mommifier {
public String mommify(String word) {
return word;
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {
String word = "str";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("str", mommifiedWord);
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {
String word = "a";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("mommy", mommifiedWord);
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {
String word = "a";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("mommy", mommifiedWord);
}
}
SOURCE
public class Mommifier {
public String mommify(String word) {
for (char character : word.toCharArray()) {
if (character == 'a'
|| character == 'e'
|| character == 'i'
|| character == 'o'
|| character == 'u'){
return "mommy";
}
}
return word;
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {
String word = "a";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("mommy", mommifiedWord);
}
}
SOURCE
public class Mommifier {
public String mommify(String word) {
for (char character : word.toCharArray()) {
if (character == 'a'
|| character == 'e'
|| character == 'i'
|| character == 'o'
|| character == 'u'){
return "mommy";
}
}
return word;
}
}
SOURCE
public class Mommifier {
private static final String VOWELS = "aeiou";
private static final String REPLACEMENT_WORD = "mommy";
public String mommify(String word) {
for (Character character : word.toCharArray()) {
if (isAVowel(character)) {
return REPLACEMENT_WORD;
}
}
return word;
}
private boolean isAVowel(Character character) {
return VOWELS.contains(character.toString());
}
}
TEST
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MommifierTest {
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {
String word = "a";
Mommifier mommifier = new Mommifier();
String mommifiedWord = mommifier.mommify(word);
assertEquals("mommy", mommifiedWord);
}
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {
mommifier = new Mommifier();
}
@Test
public void shouldNotMommifyEmptyString() {
assertEquals("", mommifier.mommify(""));
}
@Test
public void shouldNotMommifyWordsWithNoVowels() {
assertEquals("str", mommifier.mommify("str"));
}
@Test
public void shouldMommifyVowel() {
assertEquals("mommy", mommifier.mommify("a"));
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {
mommifier = new Mommifier();
}
@Test
public void shouldNotMommifyEmptyString() {
assertEquals("", mommifier.mommify(""));
}
@Test
public void shouldNotMommifyWordsWithNoVowels() {
assertEquals("str", mommifier.mommify("str"));
}
@Test
public void shouldMommifyVowel() {
assertEquals("mommy", mommifier.mommify("a"));
}
TEST
import ...;
public class MommifierTest {
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {
assertEquals("blmommy", mommifier.mommify("bla"));
}
}
TEST
import ...;
public class MommifierTest {
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {
assertEquals("blmommy", mommifier.mommify("bla"));
}
}
SOURCE
public class Mommifier {
private static final String VOWELS = "aeiou";
private static final String REPLACEMENT_WORD = "mommy";
public String mommify(String word) {
String mommifiedWord = "";
for (Character character : word.toCharArray()) {
if (isAVowel(character)) {
mommifiedWord += REPLACEMENT_WORD;
} else {
mommifiedWord += character;
}
}
return mommifiedWord;
}
private boolean isAVowel(Character character) {
return VOWELS.contains(character.toString());
}
}
TEST
import ...;
public class MommifierTest {
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {
assertEquals("blmommy", mommifier.mommify("bla"));
}
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {
assertEquals("blah", mommifier.mommify("blah"));
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {
assertEquals("blah", mommifier.mommify("blah"));
}
SOURCE
...
private static final double THRESHOLD = 0.3;
public String mommify(String word) {
int vowelCount = 0;
String mommifiedWord = "";
for (Character character : word.toCharArray()) {
if (isAVowel(character)) {
mommifiedWord += REPLACEMENT_WORD;
vowelCount++;
} else {
mommifiedWord += character;
}
}
if((double)vowelCount/word.toCharArray().length
< THRESHOLD){
return word;
}
return mommifiedWord;
}
...
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {
assertEquals("blah", mommifier.mommify("blah"));
}
SOURCE
public String mommify(String word) {
if(vowelCountLessThanThreshold(word)){
return word;
}
return replaceVowels(word);
}
private boolean vowelCountLessThanThreshold(String word){...}
private String replaceVowels(String word) {...}
private boolean isAVowel(Character character) {...}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {
assertEquals("blah", mommifier.mommify("blah"));
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {
assertEquals("blmommyh”, mommifier.mommify("blaah"));
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {
assertEquals("blmommyh”, mommifier.mommify("blaah"));
}
SOURCE
...
public String mommify(String word) {...}
private String replaceVowels(String word) {
String mommifiedWord = "";
for (Character character : word.toCharArray()) {
if (!isVowel(character)) {
mommifiedWord += character;
} else if(!mommifiedWord.endsWith(REPLACEMENT_WORD)){
mommifiedWord += REPLACEMENT_WORD;
}
}
return mommifiedWord;
}
private boolean vowelCountLessThanThreshold(String word){...}
private boolean isVowel(Character character) {...}
...
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {
assertEquals("blmommyh”, mommifier.mommify("blaah"));
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {
assertEquals("blmommyhmommy”, mommifier.mommify("blaha"));
}
TEST
private Mommifier mommifier;
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {
assertEquals("blmommyhmommy”, mommifier.mommify("blaha"));
}
TEST
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {...}
@Test
public void shouldMommifyCapitalVowels() {
assertEquals("BLmommy", mommifier.mommify("BLA"));
}
TEST
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {...}
@Test
public void shouldMommifyCapitalVowels() {
assertEquals("BLmommy", mommifier.mommify("BLA"));
}
SOURCE
public class Mommifier {
private static final String VOWELS = "aeiou";
private static final String REPLACEMENT_WORD = "mommy";
private static final double THRESHOLD = 0.3;
public String mommify(String word) {...}
private String replaceVowels(String word) {...}
private boolean vowelCountLessThanThreshold(String word){...}
private boolean isVowel(Character character) {
Character lowerCase = Character.toLowerCase(character);
return VOWELS.contains(lowerCase.toString());
}
}
TEST
@Before
public void setUp() {...}
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {...}
@Test
public void shouldMommifyCapitalVowels() {
assertEquals("BLmommy", mommifier.mommify("BLA"));
}
TEST
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {...}
@Test
public void shouldMommifyCapitalVowels() {...}
@Test(expected = NullPointerException.class)
public void shouldErrorOnNull() {
mommifier.mommify(null);
}
TEST
@Test
public void shouldNotMommifyEmptyString() {...}
@Test
public void shouldNotMommifyWordsWithNoVowels() {...}
@Test
public void shouldMommifyVowel() {...}
@Test
public void shouldMommifyConsonantsAndSingleVowel() {...}
@Test
public void shouldNotMommifyLessThan30PercentVowels() {...}
@Test
public void shouldMommifyContinuousVowelsOnlyOnce() {...}
@Test
public void shouldMommifyMultipleSetsOfVowels() {...}
@Test
public void shouldMommifyCapitalVowels() {...}
@Test(expected = NullPointerException.class)
public void shouldErrorOnNull() {
mommifier.mommify(null);
}
TEST CASES
“” → “”
“str” → “str”
“a” → “mommy”
“blah” → “blah”
“bla” → “blmommy”
“blaa” → “blmommy”
“blaaha” → “blmommyhmommy”
“blA” → “blmommy”
Null → raise exception
TEST CASES
public void shouldNotMommifyEmptyString
public void shouldNotMommifyWordsWithNoVowels
public void shouldMommifyVowel
public void shouldMommifyConsonantsAndSingleVowel
public void shouldNotMommifyLessThan30PercentVowels
public void shouldMommifyContinuousVowelsOnlyOnce
public void shouldMommifyMultipleSetsOfVowels
public void shouldMommifyCapitalVowels
public void shouldErrorOnNull
TOP DOWN TESTING
SOME USEFUL BOOKS
THANK YOU
Gabriel Gavasso
Anand Iyengar
Thao Dang
Hung Dang
Mommifier Dojo by TWU team

More Related Content

PPT
Sviluppo percettivo-motorio
PDF
Tdd in android (mvp)
PDF
Android TDD
PPTX
TDD - Agile
PDF
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
PPTX
Test-Driven Development (TDD)
PDF
Test Driven Development (TDD)
PPT
TDD - Ketan Soni
Sviluppo percettivo-motorio
Tdd in android (mvp)
Android TDD
TDD - Agile
Overview on TDD (Test Driven Development) & ATDD (Acceptance Test Driven Deve...
Test-Driven Development (TDD)
Test Driven Development (TDD)
TDD - Ketan Soni

Similar to TDD for the Win (20)

PDF
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
PPTX
Navigating the xDD Alphabet Soup
PPTX
Tomasz Polanski - Droidcon Berlin 2016
PPTX
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
PPS
Bdd: Tdd and beyond the infinite
PDF
tdd-2013-calpoly.pdf
PDF
Introduction to TDD (Test Driven development) - Ahmed Shreef
PPT
jUnit
PDF
Reloaded
PDF
Confitura 2012 Bad Tests, Good Tests
PPT
05 junit
PDF
DOES NOT NEED TO BE ANSWERED UNTIL NOV 13thWords AssignmentRober.pdf
PDF
Unit Testing Standards - Recommended Best Practices
PDF
Test string and array
PDF
Testing Java Code Effectively - BaselOne17
PPTX
Dat testing - An introduction to Java and Android Testing
PDF
Operator Overloading In Scala
PDF
Improve your tests in the CI with STAMP, OW2con'19, June 12-13, 2019, Paris
 
PDF
Improve your tests in the CI with STAMP, OW2con'19, June 12-13, Paris.
 
PDF
GeeCON 2012 Bad Tests, Good Tests
Tomasz Polanski - Automated mobile testing 2016 - Testing: why, when, how
Navigating the xDD Alphabet Soup
Tomasz Polanski - Droidcon Berlin 2016
JDD 2016 - Sebastian Malaca - You Dont Need Unit Tests
Bdd: Tdd and beyond the infinite
tdd-2013-calpoly.pdf
Introduction to TDD (Test Driven development) - Ahmed Shreef
jUnit
Reloaded
Confitura 2012 Bad Tests, Good Tests
05 junit
DOES NOT NEED TO BE ANSWERED UNTIL NOV 13thWords AssignmentRober.pdf
Unit Testing Standards - Recommended Best Practices
Test string and array
Testing Java Code Effectively - BaselOne17
Dat testing - An introduction to Java and Android Testing
Operator Overloading In Scala
Improve your tests in the CI with STAMP, OW2con'19, June 12-13, 2019, Paris
 
Improve your tests in the CI with STAMP, OW2con'19, June 12-13, Paris.
 
GeeCON 2012 Bad Tests, Good Tests
Ad

More from Thoughtworks (20)

PDF
Design System as a Product
PDF
Designers, Developers & Dogs
PDF
Cloud-first for fast innovation
PDF
More impact with flexible teams
PDF
Culture of Innovation
PDF
Dual-Track Agile
PDF
Developer Experience
PDF
When we design together
PDF
Hardware is hard(er)
PDF
Customer-centric innovation enabled by cloud
PDF
Amazon's Culture of Innovation
PDF
When in doubt, go live
PDF
Don't cross the Rubicon
PDF
Error handling
PDF
Your test coverage is a lie!
PDF
Docker container security
PDF
Redefining the unit
PPTX
Technology Radar Webinar UK - Vol. 22
PDF
A Tribute to Turing
PDF
Rsa maths worked out
Design System as a Product
Designers, Developers & Dogs
Cloud-first for fast innovation
More impact with flexible teams
Culture of Innovation
Dual-Track Agile
Developer Experience
When we design together
Hardware is hard(er)
Customer-centric innovation enabled by cloud
Amazon's Culture of Innovation
When in doubt, go live
Don't cross the Rubicon
Error handling
Your test coverage is a lie!
Docker container security
Redefining the unit
Technology Radar Webinar UK - Vol. 22
A Tribute to Turing
Rsa maths worked out
Ad

Recently uploaded (20)

PPTX
Tartificialntelligence_presentation.pptx
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
Enhancing emotion recognition model for a student engagement use case through...
PDF
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
PDF
Getting Started with Data Integration: FME Form 101
PDF
Hybrid model detection and classification of lung cancer
PDF
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
PDF
WOOl fibre morphology and structure.pdf for textiles
PPTX
OMC Textile Division Presentation 2021.pptx
PPTX
Group 1 Presentation -Planning and Decision Making .pptx
PDF
Zenith AI: Advanced Artificial Intelligence
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Mushroom cultivation and it's methods.pdf
PDF
1 - Historical Antecedents, Social Consideration.pdf
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PPTX
A Presentation on Artificial Intelligence
PDF
Encapsulation theory and applications.pdf
PDF
A comparative study of natural language inference in Swahili using monolingua...
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PDF
NewMind AI Weekly Chronicles - August'25-Week II
Tartificialntelligence_presentation.pptx
Univ-Connecticut-ChatGPT-Presentaion.pdf
Enhancing emotion recognition model for a student engagement use case through...
From MVP to Full-Scale Product A Startup’s Software Journey.pdf
Getting Started with Data Integration: FME Form 101
Hybrid model detection and classification of lung cancer
Microsoft Solutions Partner Drive Digital Transformation with D365.pdf
WOOl fibre morphology and structure.pdf for textiles
OMC Textile Division Presentation 2021.pptx
Group 1 Presentation -Planning and Decision Making .pptx
Zenith AI: Advanced Artificial Intelligence
Building Integrated photovoltaic BIPV_UPV.pdf
Mushroom cultivation and it's methods.pdf
1 - Historical Antecedents, Social Consideration.pdf
gpt5_lecture_notes_comprehensive_20250812015547.pdf
A Presentation on Artificial Intelligence
Encapsulation theory and applications.pdf
A comparative study of natural language inference in Swahili using monolingua...
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
NewMind AI Weekly Chronicles - August'25-Week II

TDD for the Win

  • 1. TDD FOR THE WIN Basics to Test Driven Development May 2014 Minh Ngoc Dang
  • 2. Senior Developer at ThoughtWorks ThoughtWorks University Trainer Minh Ngoc Dang
  • 4. WHY TESTING? Lots of reasons! Here are a select few Verify functionality of application Catch bugs and prevent them from coming back Serve as documentation for maintainability purposes
  • 5. BUT WHAT ABOUT…? ? How do we make sure we have full test coverage? ? How can we be confident all cases are covered? ? How can we prevent bugs from happening?
  • 10. TEST DRIVING MEANS Writing tests before writing code Write the minimum amount of code necessary to make tests pass Rinse and repeat
  • 12. WHY TDD? Back to previously posed questions Test Coverage? Cases Covered? Bug Prevention?
  • 14. TEST COVERAGE Tests written before code Ensure all code covered by tests
  • 15. TEST COVERAGE Tests written before code Ensure all code covered by tests High test coverage
  • 16. WHY TDD? Back to previously posed questions Test Coverage? Cases Covered? Bug Prevention?
  • 17. TEST CASES Test cases reflect exactly what code does
  • 18. TEST CASES Test cases reflect exactly what code does Visible list of functionality
  • 19. TEST CASES Test cases reflect exactly what code does Visible list of functionality Easy to see which cases are missing
  • 20. WHY TDD? Back to previously posed questions Test Coverage? Cases Covered? Bug Prevention?
  • 21. BUG PREVENTION Mental shift in thinking up test case before code
  • 22. BUG PREVENTION Mental shift in thinking up test case before code Encourage edge case testing
  • 23. BUG PREVENTION Mental shift in thinking up test case before code Encourage edge case testing Help prevent bugs in edge cases
  • 24. WHY TDD? Back to previously posed questions Test Coverage? Cases Covered? Bug Prevention?
  • 26. TIME SAVER Ease in debugging Confidence in refactoring
  • 27. DRIVING DESIGN Help define usage – How should the code be used? Only write necessary code – YAGNI!
  • 28. SO HOW CAN I TDD?
  • 29. RED – GREEN - REFACTOR New Test New Test New Test Red GreenRefactor Red GreenRefactor Red GreenRefactor
  • 30. EXAMPLE You are given strings of different lengths. If the number of vowels are more than 30% of the string length then insert ‘mommy’ for each continuous set of vowels.  his → hmommys  hear → hmommyr ✗ hear → hmommymommyr
  • 31. TEST CASES “” → “” // empty string “str” → “str” // no vowels “a” → “mommy” // single vowel “blah” → “blah” // < 30% length “bla” → “blmommy” // > 30% length “blaa” → “blmommy” // continuous vowels “blaaha” → “blmommyhmommy” // multi sets of vowels “blA” → “blmommy” // capital letters Null → raise exception // null checks
  • 32. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() { String word = ""; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("", mommifiedWord); } }
  • 33. SOURCE public class Mommifier { public String mommify(String word) { return null; } }
  • 34. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() { String word = ""; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("", mommifiedWord); } }
  • 35. SOURCE public class Mommifier { public String mommify(String word) { return ""; } }
  • 36. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() { String word = ""; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("", mommifiedWord); } }
  • 37. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() { String word = "str"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("str", mommifiedWord); } }
  • 38. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() { String word = "str"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("str", mommifiedWord); } }
  • 39. SOURCE public class Mommifier { public String mommify(String word) { return word; } }
  • 40. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() { String word = "str"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("str", mommifiedWord); } }
  • 41. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() { String word = "a"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("mommy", mommifiedWord); } }
  • 42. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() { String word = "a"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("mommy", mommifiedWord); } }
  • 43. SOURCE public class Mommifier { public String mommify(String word) { for (char character : word.toCharArray()) { if (character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u'){ return "mommy"; } } return word; } }
  • 44. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() { String word = "a"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("mommy", mommifiedWord); } }
  • 45. SOURCE public class Mommifier { public String mommify(String word) { for (char character : word.toCharArray()) { if (character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u'){ return "mommy"; } } return word; } }
  • 46. SOURCE public class Mommifier { private static final String VOWELS = "aeiou"; private static final String REPLACEMENT_WORD = "mommy"; public String mommify(String word) { for (Character character : word.toCharArray()) { if (isAVowel(character)) { return REPLACEMENT_WORD; } } return word; } private boolean isAVowel(Character character) { return VOWELS.contains(character.toString()); } }
  • 47. TEST import org.junit.Test; import static org.junit.Assert.assertEquals; public class MommifierTest { @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() { String word = "a"; Mommifier mommifier = new Mommifier(); String mommifiedWord = mommifier.mommify(word); assertEquals("mommy", mommifiedWord); } }
  • 48. TEST private Mommifier mommifier; @Before public void setUp() { mommifier = new Mommifier(); } @Test public void shouldNotMommifyEmptyString() { assertEquals("", mommifier.mommify("")); } @Test public void shouldNotMommifyWordsWithNoVowels() { assertEquals("str", mommifier.mommify("str")); } @Test public void shouldMommifyVowel() { assertEquals("mommy", mommifier.mommify("a")); }
  • 49. TEST private Mommifier mommifier; @Before public void setUp() { mommifier = new Mommifier(); } @Test public void shouldNotMommifyEmptyString() { assertEquals("", mommifier.mommify("")); } @Test public void shouldNotMommifyWordsWithNoVowels() { assertEquals("str", mommifier.mommify("str")); } @Test public void shouldMommifyVowel() { assertEquals("mommy", mommifier.mommify("a")); }
  • 50. TEST import ...; public class MommifierTest { private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() { assertEquals("blmommy", mommifier.mommify("bla")); } }
  • 51. TEST import ...; public class MommifierTest { private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() { assertEquals("blmommy", mommifier.mommify("bla")); } }
  • 52. SOURCE public class Mommifier { private static final String VOWELS = "aeiou"; private static final String REPLACEMENT_WORD = "mommy"; public String mommify(String word) { String mommifiedWord = ""; for (Character character : word.toCharArray()) { if (isAVowel(character)) { mommifiedWord += REPLACEMENT_WORD; } else { mommifiedWord += character; } } return mommifiedWord; } private boolean isAVowel(Character character) { return VOWELS.contains(character.toString()); } }
  • 53. TEST import ...; public class MommifierTest { private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() { assertEquals("blmommy", mommifier.mommify("bla")); } }
  • 54. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() { assertEquals("blah", mommifier.mommify("blah")); }
  • 55. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() { assertEquals("blah", mommifier.mommify("blah")); }
  • 56. SOURCE ... private static final double THRESHOLD = 0.3; public String mommify(String word) { int vowelCount = 0; String mommifiedWord = ""; for (Character character : word.toCharArray()) { if (isAVowel(character)) { mommifiedWord += REPLACEMENT_WORD; vowelCount++; } else { mommifiedWord += character; } } if((double)vowelCount/word.toCharArray().length < THRESHOLD){ return word; } return mommifiedWord; } ...
  • 57. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() { assertEquals("blah", mommifier.mommify("blah")); }
  • 58. SOURCE public String mommify(String word) { if(vowelCountLessThanThreshold(word)){ return word; } return replaceVowels(word); } private boolean vowelCountLessThanThreshold(String word){...} private String replaceVowels(String word) {...} private boolean isAVowel(Character character) {...}
  • 59. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() { assertEquals("blah", mommifier.mommify("blah")); }
  • 60. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() { assertEquals("blmommyh”, mommifier.mommify("blaah")); }
  • 61. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() { assertEquals("blmommyh”, mommifier.mommify("blaah")); }
  • 62. SOURCE ... public String mommify(String word) {...} private String replaceVowels(String word) { String mommifiedWord = ""; for (Character character : word.toCharArray()) { if (!isVowel(character)) { mommifiedWord += character; } else if(!mommifiedWord.endsWith(REPLACEMENT_WORD)){ mommifiedWord += REPLACEMENT_WORD; } } return mommifiedWord; } private boolean vowelCountLessThanThreshold(String word){...} private boolean isVowel(Character character) {...} ...
  • 63. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() { assertEquals("blmommyh”, mommifier.mommify("blaah")); }
  • 64. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() { assertEquals("blmommyhmommy”, mommifier.mommify("blaha")); }
  • 65. TEST private Mommifier mommifier; @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() { assertEquals("blmommyhmommy”, mommifier.mommify("blaha")); }
  • 66. TEST @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() {...} @Test public void shouldMommifyCapitalVowels() { assertEquals("BLmommy", mommifier.mommify("BLA")); }
  • 67. TEST @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() {...} @Test public void shouldMommifyCapitalVowels() { assertEquals("BLmommy", mommifier.mommify("BLA")); }
  • 68. SOURCE public class Mommifier { private static final String VOWELS = "aeiou"; private static final String REPLACEMENT_WORD = "mommy"; private static final double THRESHOLD = 0.3; public String mommify(String word) {...} private String replaceVowels(String word) {...} private boolean vowelCountLessThanThreshold(String word){...} private boolean isVowel(Character character) { Character lowerCase = Character.toLowerCase(character); return VOWELS.contains(lowerCase.toString()); } }
  • 69. TEST @Before public void setUp() {...} @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() {...} @Test public void shouldMommifyCapitalVowels() { assertEquals("BLmommy", mommifier.mommify("BLA")); }
  • 70. TEST @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() {...} @Test public void shouldMommifyCapitalVowels() {...} @Test(expected = NullPointerException.class) public void shouldErrorOnNull() { mommifier.mommify(null); }
  • 71. TEST @Test public void shouldNotMommifyEmptyString() {...} @Test public void shouldNotMommifyWordsWithNoVowels() {...} @Test public void shouldMommifyVowel() {...} @Test public void shouldMommifyConsonantsAndSingleVowel() {...} @Test public void shouldNotMommifyLessThan30PercentVowels() {...} @Test public void shouldMommifyContinuousVowelsOnlyOnce() {...} @Test public void shouldMommifyMultipleSetsOfVowels() {...} @Test public void shouldMommifyCapitalVowels() {...} @Test(expected = NullPointerException.class) public void shouldErrorOnNull() { mommifier.mommify(null); }
  • 72. TEST CASES “” → “” “str” → “str” “a” → “mommy” “blah” → “blah” “bla” → “blmommy” “blaa” → “blmommy” “blaaha” → “blmommyhmommy” “blA” → “blmommy” Null → raise exception
  • 73. TEST CASES public void shouldNotMommifyEmptyString public void shouldNotMommifyWordsWithNoVowels public void shouldMommifyVowel public void shouldMommifyConsonantsAndSingleVowel public void shouldNotMommifyLessThan30PercentVowels public void shouldMommifyContinuousVowelsOnlyOnce public void shouldMommifyMultipleSetsOfVowels public void shouldMommifyCapitalVowels public void shouldErrorOnNull
  • 76. THANK YOU Gabriel Gavasso Anand Iyengar Thao Dang Hung Dang Mommifier Dojo by TWU team

Editor's Notes

  • #2: This talk will be mainly about what benefits Test Driven Development brings and includes a practical example.
  • #4: Before we start on TDD, let’s quickly look at testing
  • #5: Why do we test? For a number of reasons! Testing allows us to verify the behaviour of software and ensures these are not changed unintentionally. It allows us to track bugs. Call out the possible ones and having a test in place prevents it from coming back. It also serves as documentation for the current state of the software.
  • #6: But if we add tests after we have completed a functionality… How do we make sure we have full test coverage? How can we be confident all cases are covered? How can we prevent bugs from happening in the first place?
  • #7: This is where TDD comes in!
  • #8: … or Test Driven Development!
  • #9: But wait…
  • #10: … what exactly does TDD even mean?
  • #11: Test driving means… We write the tests before implementing the code. And then we write the minimum amount of code possible to make this single test pass – baby steps. Then we write another test and the process repeats.
  • #12: But why test first?
  • #13: Let’s go back to the questions we asked previously for writing tests after: How can we be more confident about: Test coverage Test cases covered Preventing bugs
  • #14: Tests written before implementing code
  • #15: Means that all the code you write should be covered by a test. Writing minimum amount of code to make tests pass means that you won’t have untested code.
  • #16: This will result in higher test coverage
  • #17: So yay. What about test cases?
  • #18: Writing tests first and having high code coverage means the tests reflect exactly what the code does.
  • #19: Having a very visible list of the current functionality of the software…
  • #20: …allows you to see which cases are tested and which are missing
  • #21: Finally bug prevention
  • #22: TDD creates a mental shift in having more focus on test cases
  • #23: When we can see all currently tested cases and try and think about which cases are missing it encourages people to think about the edge cases where the software is likely to fail
  • #24: And what we expect to happen in these cases.
  • #25: TDD helps address all these questions…
  • #26: But that’s not all
  • #27: Having a high level of test coverage means that it is much easier to debug. Just need to go to the test case you want and debug that. This also ensures that we are not breaking functionality when refactoring. Allowing people to be more confident to make bolder and more risky refactorings.
  • #28: TDD also helps drive out the design of the software. When you write tests first, you think about the usage of the code before writing it, making it more usable. Writing only a minimum necessary amount of code means there are no unnecessary functionality that needs support. You ain’t gonna need it!
  • #29: Now that we’ve been through why.. Let’s talk about the how
  • #30: Red – Green – Refactor. Write the test, see your code fail for the right reasons to make sure you’re testing the right thing (red) Make the test pass (green) Only refactor while the tests are green Write a new test and repeat the process
  • #31: Let’s go through a coding example of TDD
  • #32: Thinking up different possible test cases
  • #33: Let’s start with a test. Since the implementation does not exist, it will not compile.
  • #34: Make the code compile
  • #35: Now the test fails for the right reason
  • #36: Minimum step necessary to make it pass.
  • #37: And it passes
  • #38: Now we need another test case to force us to add more functionality to the code
  • #39: It fails for the right reason
  • #40: Again minimum amount of code to make it pass – remembering to keep the old tests passing too.
  • #41: And they pass
  • #42: Adding actual replacement of vowels.
  • #43: It fails for the right reason
  • #44: And the logic for vowel replacement is added
  • #45: Tests all pass
  • #46: Now that tests pass we can go ahead and refactor
  • #47: Notice the logic has changed. It’s a step for us to improve our design.
  • #48: Tests still pass
  • #49: Since tests are also code we can refactor this too
  • #50: And they still pass
  • #51: Adding new tests for actual replace mixed vowels and consonants
  • #52: It fails for the right reason
  • #53: And we modify the code to make it pass.
  • #54: And all tests including old ones still work
  • #55: Now for the logic of not replacing vowels if it’s less than 30%
  • #56: It fails for the right reason
  • #57: we modify the code to make the tests pass
  • #58: It does
  • #59: We can then go and refactor the code to make it more readable and maintainable
  • #60: Making sure our tests still pass
  • #61: Continuous vowels
  • #62: Fails for the right reason
  • #63: Adding logic
  • #64: Tests pass
  • #65: How about multiple sets of vowels in a word?
  • #66: It passes since our code already works with this scenario. Sometimes people like to change the code to see it fail just to make sure it’s passing for the right reason and not because of some coincidence.
  • #67: How about capital letters?
  • #68: It fails.
  • #69: Again making it pass
  • #70: And it does
  • #71: Null checks?
  • #72: It already passes because runtime exceptions.
  • #73: And we’re done! Let’s look at all the test cases we came up before.
  • #74: The tests now serve as documentations of these functionality.
  • #75: In terms of writing different types of tests, I personally prefer to Test Drive from ‘Top down” This means starting out writing higher level tests such as functional tests or integration tests and then using this to drive out your unit tests. And having your unit tests then drive out the implementation.
  • #76: Here are some books if you’re interested in reading more about TDD: Test Driven Development by example by Kent Beck Refactoring by Martin Fowler
  • #77: Special thanks – any questions?