tags:

views:

1011

answers:

3

In the notorious stackoverflow #38 Joel talked about how difficult it would be to do TDD for something like JPEG compression. Bob Martin wanted to cover how to do TDD for an instance such as that during podcast #41 but I don't think they ever got to it. Thus:

How would one go about using TDD to develop and test jpeg compression?

+3  A: 

If you think TDD means tests come before any code or any design, it's largely impossible. For complex algorithms, you need some results. And in the case of compression, the results are hard to produce by hand. Not impossible, but hard.

Further, compression requires a very high-performance algorithm. Simply passing a test isn't quite good enough. Many low-performance algorithms can pass the basic "correctness" test.

To move beyond correctness, you need evidence that your algorithm is optimal. This can only be developed outside the testing world-view. You need a complexity analysis using O( something ), which isn't the results of a test; nor can it be well-defined as the results of a test.

If, on the other hand, you think "testability" comes before most of the code, then it's easy.

  • Design your algorithm. Write a proof that it's optimal.

  • Write some code that exposes critical pieces of your algorithm as testable modules.

  • In some cases, write code to produce test results for the overall algorithm. This can be sub-optimal, brute-force code that produces the right answer through really obvious, but slow algorithms.

  • Assemble a unittest to show that your implementation produces the expected test results.

  • Assemble a technical paper to show that it's also optimal.

It's not test-first. But it is test-driven.

S.Lott
+52  A: 

Joel's question was something like this. Suppose you wanted to set a bit somewhere that caused a low resolution image to be displayed rather than a high resolution image. How would you use TDD to get that to work? Would you write a test that scraped the screen to show that the image was in low res?

Of course not. You already know that the JPEG library works. You already know that if you call it with the right arguments it will display in low resolution. What you need to test is that the bit you set gets translated into the appropriate calls to the JPEG library. So you mock out the JPEG library with a very simple module controlled by your test. Then you set the bit, and request display. The Mocked JPEG library will remember how it was called, and then the test can check to be sure that it was called correctly.

OK, so how would you test the internals of the JPEG library? I don't know a lot about JPEG rendering, but I presume it's about compression, decompression and bitmaps. Compression and decompression are just algorithms. Algorithms have predictable outputs from given inputs. So you set up a series of very simple inputs and make sure you get the predictable outputs. You set up the inputs so that the internals of the JPEG algorithms are covered. The same logic holds for the bitmaps. You don't have to render them on the screen. Simple little bitmaps can be rendered into memory buffers that the tests can examine. By simple, I mean SIMPLE. 3X3, 5X5, 8X8. Simple. Again, you structure your input data to cover the bulk of the code.

None of this is rocket science. None if it is perfect. But a suite of 50 tests that demonstrates that 90% of your logic is correct can make a huge difference when you want to make changes.

Can you ever completely eliminate manual testing? Of course not. But you can significantly mitigate it. You can reduce manual testing to a few very strategic tests rather than thousands of painfully tedious test plans.

Uncle Bob
Awesome, I got Uncle Bob to join stackoverflow. There should be a badge for this.
stimms
Haha...well since you won't get a badge for it, I'll at least give your question a +1.
Kyle Walsh
You can render more complex images and then compute a MD5 checksum for comparing to known results.
Todd Smith
A: 

Test driven development is not only programming, there are many other things you can do using test first, examples are with acceptance tdd, etc.

Think first how you want it to behave, this is the thing. For an algorithm, an example could be something like:

  • "It must complete 5 calls in 10 seconds"
  • "It must reduce to 10% the size of the image"
  • Others.

I believe it is only a way of life to think clearly what you want to accomplish :D

arielsan