A “post(Test Driven Design vs. Design by Contract)”:http://creativekarma.com/more.php?id=80_0_1_0_M by Doug over at Creative Karma takes issue with the fact that I consider Test-Driven Development to be “quite similar(Test-Driven Development vs Design By Contract)”:http://www.magpiebrain.com/archives/000191.html to Design by Contract. After reading over the piece, I have to agree that at Doug is correct. What I meant to say is that you can almost consider TDD to be a subset (or variation of a subset) of Design by Contract.
What do I mean by that? Well, in TDD you start of with a goal. This goal tends to be fairly specific, but of course comes from a larger idea of what the system should do (most TDD texts seem to skip the part where these specific tasks actually come from, as I’ll do here). This is typically something like (to borrow Kent Beck’s example) “I need to be able to add 5 US dollars to 10 Euros and get a result of 20 Euros if the dollar to euro exchange rate is 1:2”. The developer then breaks this down into solvable tests, which lead to the code being implemented. Each little unit we are defining the tests that let us know the code is working – with Contract By Design you can define pre and post-conditions (this needs to be true before, this needs to be true afterwards). At this level the similarity between the two is clear. However Contract By Design goes far beyond this small scope, to define class invariants, loop invariants etc. I’m not saying one is better than the other, but I do feel they share some of the same benefits.
Doug finishes up thus:
Not only are unit tests black box, they also only test certain cases. A contract specifies the required behavior for every case, and any assertion associated with that contract verifies that the behavior is correct for every case that is encountered. That is what Bertrand Meyer was referring to when he said, “A test checks one case. A contract describes the abstract specification for all cases.”
I agree completely – and this is the point that Bertrand Meyer was making when he talked about systematic testing:
It was shown many years ago through a very simple argument that there’s no such thing as an exhaustive test, a test that exercises all possible cases. So we know we can’t have an exhaustive test, but we can have systematic tests that have a likelihood of exercising the cases that will fail. For example, if you have a parameter that must be between certain bounds, then you want to test the values close to bounds of the range. You want to test maybe the value in the middle, and maybe a few in-between. So we want to have tests that are systematic in that sense, and contracts help a lot generating such “systematic” tests.
Unit tests are not the same as a contract, they merely attempt to prove that the code satisfies the required contract. The better the tests, the more systematic they are, the more you have proved the contract fulfilled and that the code is of decent quality. One single test is not always enough for you to strike that taks of your todo list. No matter what your position is on this particular topic, I think we can all agree on these two points that Doug makes in summation, which I’ll reiterate here so I don’t forget them:
- Testing cannot show the absence of defects, it can only show that defects are present.
- We cannot test quality into a product, we have to design it in.