In Test-driven development (TDD), when using the Transformation Priority Premise paradigm, you treat loops as a generalization of conditional statements.
This approach combines well with this syntax, if you consider only simple if/else
(no elif
) statements:
if cond:
# 1
else:
# 2
generalizes to:
while cond: # <-- generalization
# 1
else:
# 2
nicely.
In other languages, TDD steps from a single case to cases with collections require more refactoring.
Here is an example from 8thlight blog:
In the linked article at 8thlight blog, the Word Wrap kata is considered: adding line breaks to strings (the s
variable in the snippets below) to make them fit a given width (the length
variable in the snippets below). At one point the implementation looks as follows (Java):
String result = "";
if (s.length() > length) {
result = s.substring(0, length) + "\n" + s.substring(length);
} else {
result = s;
}
return result;
and the next test, that currently fails is:
@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
}
So we have code that works conditionally: when a particular condition is met, a line break is added. We want to improve the code to handle multiple line breaks. The solution presented in the article proposes to apply the (if->while) transformation, however the author makes a comment that:
While loops can’t have else
clauses, so we need to eliminate the else
path by doing less in the if
path. Again, this is a refactoring.
which forces to do more changes to the code in the context of one failing test:
String result = "";
while (s.length() > length) {
result += s.substring(0, length) + "\n";
s = s.substring(length);
}
result += s;
In TDD we want to write as less code as possible to make tests pass. Thanks to Python's syntax the following transformation is possible:
from:
result = ""
if len(s) > length:
result = s[0:length] + "\n"
s = s[length:]
else:
result += s
to:
result = ""
while len(s) > length:
result += s[0:length] + "\n"
s = s[length:]
else:
result += s