It’s confusing to think of TDD as its own rationality technique: testing your belief that a piece of code works is not fundamentally different from testing any other belief. Okay, so that part is just running unit tests once. Since whether a piece of code works is a different belief from whether that piece of code with a few modifications works, for efficiency, since writing tests is work, you need to keep that tests around and rerun them. So, that’s unit testing. TDD is just writing your tests beforehand, which makes a difference in the process of designing software, but not really in how confident you should be that your code works.
Something more interesting to think about is how much information a test gives you that your code works. You can often tell from eyeballing whether switching an integer from positive to negative will make a meaningful difference whether the code produces the intended result.
This really turns into an approximate, poor-man’s version of proving code correct, which typically proceeds by breaking down code into its paths and checking each against the mathematical model.
Which reminds me, I have to go prove a few Standard ML functions work by Friday.
It’s confusing to think of TDD as its own rationality technique: testing your belief that a piece of code works is not fundamentally different from testing any other belief.
No rationality technique is “fundamentally different” from fixing of any other kind of incorrect beliefs. You’ve just made an absolutely general counterargument.
(With TDD, you also test that the code didn’t work before the bugfix (in the specific way), and started working as a result of it. It’s too easy to fix nonexistent problems.)
Something more interesting to think about is how much information a test gives you that your code works.
There are several tools that help to increase that amount, that test your tests in other words. They’re far from conclusive or thorough, but they can help a great deal:
Coverage testers: This technique involves running your tests and seeing which lines in your program they involve, or (for more sophisticated versions of this technique) which possible paths through your program are ran. If you have full coverage that’s no guarantee that you have thorough tests… but if you have low coverage that definitely means your tests could be improved, because there are parts of your program that aren’t being tested.
Mutation testers: These tools will randomly introduce temporary but destructive changes in your code (swapping strings for nonsense, flipping booleans, and so on), and then run the unit tests to make sure they fail. This is far from rigorous, but it can be useful; if your test is passing even though your code isn’t actually working, then that means there’s an opportunity for a bug to be introduced there without being detected.
(Darmani, you probably already know all this; I’m saying it for whoever else might be reading this discussion.)
TDD is just writing your tests beforehand, which makes a difference in the process of designing software, but not really in how confident you should be that your code works.
The advantage I’ve had with TDD over regular testing is that I find myself going down fewer dead-ends, and so being more confident that whatever I’m writing at the moment is actually helpful.
At any given time I’m supposed to only be thinking about the latest test, so I’m much more likely to be in near mode laying down one brick at a time in just the right spot than in far mode mentally sketching out the whole castle.
Something more interesting to think about is how much information a test gives you that your code works.
There are several tools that help to increase that amount, that test your tests in other words. They’re far from conclusive or thorough, but they can help a great deal:
Coverage testers: This technique involves running your tests and seeing which lines in your program they involve, or (for more sophisticated versions of this technique) which possible paths through your program are ran. If you have full coverage that’s no guarantee that you have thorough tests… but if you have low coverage that definitely means your tests could be improved, because there are parts of your program that aren’t being tested.
Mutation testers: These tools will randomly introduce temporary but destructive changes in your code (swapping strings for nonsense, flipping booleans, and so on), and then run the unit tests to make sure they fail. This is far from rigorous, but it can be useful; if your test is passing even though your code isn’t actually working, then that means there’s an opportunity for a bug to be introduced there without being detected.
(Darmani, you probably already know all this; I’m saying it for whoever else might be reading this discussion.)
It’s confusing to think of TDD as its own rationality technique: testing your belief that a piece of code works is not fundamentally different from testing any other belief. Okay, so that part is just running unit tests once. Since whether a piece of code works is a different belief from whether that piece of code with a few modifications works, for efficiency, since writing tests is work, you need to keep that tests around and rerun them. So, that’s unit testing. TDD is just writing your tests beforehand, which makes a difference in the process of designing software, but not really in how confident you should be that your code works.
Something more interesting to think about is how much information a test gives you that your code works. You can often tell from eyeballing whether switching an integer from positive to negative will make a meaningful difference whether the code produces the intended result.
This really turns into an approximate, poor-man’s version of proving code correct, which typically proceeds by breaking down code into its paths and checking each against the mathematical model.
Which reminds me, I have to go prove a few Standard ML functions work by Friday.
No rationality technique is “fundamentally different” from fixing of any other kind of incorrect beliefs. You’ve just made an absolutely general counterargument.
(With TDD, you also test that the code didn’t work before the bugfix (in the specific way), and started working as a result of it. It’s too easy to fix nonexistent problems.)
There are several tools that help to increase that amount, that test your tests in other words. They’re far from conclusive or thorough, but they can help a great deal:
Coverage testers: This technique involves running your tests and seeing which lines in your program they involve, or (for more sophisticated versions of this technique) which possible paths through your program are ran. If you have full coverage that’s no guarantee that you have thorough tests… but if you have low coverage that definitely means your tests could be improved, because there are parts of your program that aren’t being tested.
Mutation testers: These tools will randomly introduce temporary but destructive changes in your code (swapping strings for nonsense, flipping booleans, and so on), and then run the unit tests to make sure they fail. This is far from rigorous, but it can be useful; if your test is passing even though your code isn’t actually working, then that means there’s an opportunity for a bug to be introduced there without being detected.
(Darmani, you probably already know all this; I’m saying it for whoever else might be reading this discussion.)
The advantage I’ve had with TDD over regular testing is that I find myself going down fewer dead-ends, and so being more confident that whatever I’m writing at the moment is actually helpful.
At any given time I’m supposed to only be thinking about the latest test, so I’m much more likely to be in near mode laying down one brick at a time in just the right spot than in far mode mentally sketching out the whole castle.
There are several tools that help to increase that amount, that test your tests in other words. They’re far from conclusive or thorough, but they can help a great deal:
Coverage testers: This technique involves running your tests and seeing which lines in your program they involve, or (for more sophisticated versions of this technique) which possible paths through your program are ran. If you have full coverage that’s no guarantee that you have thorough tests… but if you have low coverage that definitely means your tests could be improved, because there are parts of your program that aren’t being tested.
Mutation testers: These tools will randomly introduce temporary but destructive changes in your code (swapping strings for nonsense, flipping booleans, and so on), and then run the unit tests to make sure they fail. This is far from rigorous, but it can be useful; if your test is passing even though your code isn’t actually working, then that means there’s an opportunity for a bug to be introduced there without being detected.
(Darmani, you probably already know all this; I’m saying it for whoever else might be reading this discussion.)