I've heard this quite a bit when it comes to TDD, "You should always test before you code" actually I've never done full TDD or probably havent take advantage out of it, but how is it possible to test something that you havent even done???
Can you give me a clear example on how to do this??
Lately I've been thinking that this aspect of TDD is the same as the concept of programming by "wishful thinking" that I've read about in Structure and Interpretation of Computer Programs. For example, in lecture 2A of the MIT course taught by the authors, the following example is given for computing square roots as a function of fixed points:
(define (sqrt x)
(fixed-point
(lambda (y) (average (/ x y) y))
1))
This is shown before the fixed-point procedure is defined. You don't really need the definition to understand that you can use a fixed-point procedure to compute square roots. Once you see how you're going to use it, you can go about defining it.
(define (fixed-point f start)
(define tolerance 0.00001)
(define (close-enuf? u v)
(< (abs (- u v)) tolerance))
(define (iter old new)
(if (close-enuf? old new)
new
(iter new (f new))))
(iter start (f start)))
This is the same simple idea used in TDD. By writing tests for your methods before you write the methods themselves, you're showing yourself how those methods are to be used.
I too have doubts about the way the masses of the interwebs that hold test-driven development on high. While it's often a good idea, I sometimes think it is a hinderance for my workflow because mocking streaming data from a socket can sometimes be less effective than trusting that my serial port is actually working. That said, when you want to test-drive as opposed to "test-ensure" (writing unit tests afterward to prevent regressions on working code), here is what that looks like.
First, when you realize the need for a new feature or function of your software, you come up with an outline.
"My, I believe I'm going to need a function that takes a number, finds the square root, then returns that"
Now in TDD, instead of just writing the code and checking that the numbers come out right.. the TDD'er says:
"I'll write a function that that calls my non-existent function and compares the results with the ones I have in my head"
So he writes:
void testSqrt () {
if (sqrt(9.0) == 3.0) {
printf("ALL IS FINE AND DANDY HERE");
}
else {
printf("THE SYSTEM IS DOWN! THE SYSTEM IS DOWN!"); /* untz untz untz utnz */
}
}
Now, his non-existent sqrt has a purpose in life... to make sure it always returns 3 when fed a 9! The idea is that whether he writes
float sqrt(float n) {
long i; float x, y;
const float f = 1.5;
x = n/2.0;
y = n;
i = *(long *)&y;
i = 0x5f3759df-(i >> 1);
y = *(float *) &i;
y = y*(f-(x*y*y));
y = y*(f-(x*y*y));
return n * y;
}
or
float sqrt(float n) {
float n_t = n/2.0;
int i = *(int*)&n;
i = 0x5f375a86 - (i>>1);
n = *(float*)&i;
n = n*(1.5f-n_t*n*n);
return n;
}
He can always be assured that 3 is really 3 and he hasn't eaten the brown acid. I hope this is a good summation of the thought-process involved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With