TDD for the Win
-
Upload
thoughtworks -
Category
Technology
-
view
420 -
download
9
Transcript of TDD for the Win
TDD FOR THE WINBasics 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 lettersNull → raise exception // null checks
TESTimport 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); } }
SOURCEpublic class Mommifier { public String mommify(String word) { return null; } }
TESTimport 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); } }
SOURCEpublic class Mommifier { public String mommify(String word) { return ""; } }
TESTimport 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); } }
TESTimport 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); }}
TESTimport 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); }}
SOURCEpublic class Mommifier { public String mommify(String word) { return word; } }
TESTimport 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); }}
TESTimport 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); }}
TESTimport 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); }}
SOURCEpublic 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; }
}
TESTimport 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); }}
SOURCEpublic 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; }
}
SOURCEpublic 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()); }
}
TESTimport 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); }}
TESTprivate 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")); }
TESTprivate 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")); }
TESTimport ...;
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")); }}
TESTimport ...;
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")); }}
SOURCEpublic 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()); }}
TESTimport ...;
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")); }}
TESTprivate 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")); }
TESTprivate 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; }
...
TESTprivate 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) {...}
TESTprivate 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")); }
TESTprivate 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")); }
TESTprivate 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) {...}
...
TESTprivate 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")); }
TESTprivate 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")); }
TESTprivate 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")); }
SOURCEpublic 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 shouldNotMommifyEmptyStringpublic void shouldNotMommifyWordsWithNoVowelspublic void shouldMommifyVowelpublic void shouldMommifyConsonantsAndSingleVowelpublic void shouldNotMommifyLessThan30PercentVowelspublic void shouldMommifyContinuousVowelsOnlyOncepublic void shouldMommifyMultipleSetsOfVowelspublic void shouldMommifyCapitalVowelspublic void shouldErrorOnNull
TOP DOWN TESTING
SOME USEFUL BOOKS
THANK YOU
Gabriel GavassoAnand Iyengar
Thao DangHung Dang
Mommifier Dojo by TWU team