Test First
Test-First is a programming concept from the Extreme Programming guideline. Test-First is where tests are conducted before coding even takes place. A test is written assuming that a program already works. Then the test is run, and based off of the debugging errors, that will determine what variables, methods, and functions are needed to make the test pass. Only when the test passes does the person write the next test to determine what other factors are needed. In this way, coding is kept precise to prevent unnecessary extra codes (2000). As Sean Shubin put it, “The tests should drive you to write the code, the reason you write code is to get a test to succeed, and you should only write the minimal code to do so.” Test-first is helpful when requirements are already gathered. This keeps a person focused on what the whole program eventually will do. Without the requirements of what a program is supposed to do already, test-first can end up taking a long time (Beck, 2000).
Here is a partial sample of how test-first is done to make a program that converts numbers to roman numerals from Differentpla.net:
“/* toroman.cpp - convert decimal to Roman numerals.
* Roman numerals are I=1; V=5; X=10; L=50; C=100; D=500; M=1000
*/
int main(void)
{
assert(toRoman(1) == "I");
return 0;
}
Not surprisingly, this piece of code doesn't compile. The compiler doesn't know what assert or toRoman are. We'll add some code to fix this.
/* toroman.cpp - convert decimal to Roman numerals.
* Roman numerals are I=1; V=5; X=10; L=50; C=100; D=500; M=1000
*/
#include
std::string toRoman(int n);
int main(void)
{
assert(toRoman(1) == "I");
return 0;
}
This doesn't compile either. I forgot to include the
#include
#include
This time it compiles, but fails to link. I don't actually have a function called toRoman()
std::string toRoman(int n)
{
return "I";
}
This passes the first test case, despite the code being as simple as you like. We'd better add another test case.
int main(void)
{
assert(toRoman(1) == "I");
assert(toRoman(2) == "II");
return 0;
}
This fails the second test case, so we'll add some code to handle this.
int main(void)
{
assert(toRoman(0) == "");
assert(toRoman(1) == "I");
assert(toRoman(2) == "II");
return 0;
}
std::string toRoman(int n)
{
if (n == 1)
return "I";
else if (n == 2)
return "II";
return "";
}
This passes all the test cases. Because I added some code rather than have a dangling if/else, I added a test case for it. Since it passes, it's time to add another test.
assert(toRoman(0) == "");
assert(toRoman(1) == "I");
assert(toRoman(2) == "II");
assert(toRoman(3) == "III");
Unsurprisingly this fails. We'll add some code to handle it.
std::string toRoman(int n)
{
if (n == 1)
return "I";
else if (n == 2)
return "II";
else if (n == 3)
return "III";
return "";
}
All of the tests pass, so we'll try a little refactoring:
std::string toRoman(int n)
{
std::string r;
while (n--)
r += "I";
return r;
}
To check that we've not broken anything, we run the tests again. Since they all pass, we know that we've not broken anything. So we'll add another test case....”
References
Beck, Kent. “Testing First Makes the Code Testable.” 2000. First Class Software. 12 Mar 2005
“Code the Unit Test First.” 2000. 12 Mar 2005
Shubin, Sean. “Test First Guidelines.” 25 Jan 2002. XProgramming. 12 Mar. 2005
Test First: Roman Numeral Conversion. Differentpla.net. 12 Mar. 2005

0 Comments:
Post a Comment
<< Home