One Thing at a Time

We want to test-drive converting multiple characters in the tail of the word.

c2/22/SoundexTest.cpp
 
TEST_F(SoundexEncoding, ReplacesMultipleConsonantsWithDigits) {
 
ASSERT_THAT(soundex.encode(​"Acdl"​), Eq(​"A234"​));
 
}

A simple solution would involve iterating through all but the first letter of the word, converting each. But our code isn’t quite structured in a way that easily supports that. Let’s restructure the code.

One thing at a time, however. When test-driving, you want to keep each step in the cycle distinct. When writing a test, don’t go off and refactor. Don’t refactor when trying to get a test to pass, either. Combining the two activities will waste your time when things go awry, which they will.

We comment out the test we just wrote, temporarily halting our “red” activity. (In Google Mock, prepending DISABLED_ to the test name tells Google Mock to skip executing it. See Disabling Tests, to read about the implications of disabling tests.)

c2/23/SoundexTest.cpp
*
TEST_F(SoundexEncoding, DISABLED_ReplacesMultipleConsonantsWithDigits) {
 
ASSERT_THAT(soundex.encode(​"Acdl"​), Eq(​"A234"​));
 
}

We focus on refactoring activity and rework our solution a little. Rather than pass the entire word to encodedDigits, we pass it the tail of the word—all characters except the first. Passing only the tail should simplify the code we’ll need to iterate through the letters to be converted. It also allows us to use a couple string functions that help clarify what the code does: empty and front.

c2/23/Soundex.h
 
std::​string​ encode(​const​ std::​string​& word) ​const​ {
*
return​ zeroPad(head(word) + encodedDigits(tail(word)));
 
}
 
 
private​:
 
// ...
*
std::​string​ tail(​const​ std::​string​& word) ​const​ {
*
return​ word.substr(1);
*
}
 
 
std::​string​ encodedDigits(​const​ std::​string​& word) ​const​ {
*
if​ (word.empty()) ​return​ ​""​;
*
return​ encodedDigit(word.front());
 
}

We run our tests again to ensure our changes break no tests. That ends the refactoring activity.

We return to the start of the TDD cycle by reenabling ReplacesMultipleConsonantsWithDigits and watching it fail. We get our tests to pass by using a range-based for loop to iterate the tail of the word.

c2/24/Soundex.h
 
std::​string​ encodedDigits(​const​ std::​string​& word) ​const​ {
 
if​ (word.empty()) ​return​ ​""​;
 
*
std::​string​ encoding;
*
for​ (​auto​ letter: word) encoding += encodedDigit(letter);
*
return​ encoding;
 
}

Now that we’ve added a loop to encodedDigits, we think we don’t need the guard clause to return early if the word passed in is empty. As a refactoring step, we remove it.

c2/25/Soundex.h
 
std::​string​ encodedDigits(​const​ std::​string​& word) ​const​ {
 
std::​string​ encoding;
 
for​ (​auto​ letter: word) encoding += encodedDigit(letter);
 
return​ encoding;
 
}

We rerun our tests. Success! Deleting unnecessary code is extremely satisfying, but only when we can do so with confidence. Having tests to try these little bits of cleanup rocks.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.145.82