what are good testing / debugging practices?

Started by
2 comments, last by ToohrVyk 18 years, 2 months ago
I'm not really sure what I'm looking for, but I want a better way to test and / or debug my code as I write it. The way I do it now is simply a combination of returning false on errors, logging error messages and writing small test code to see if it works. However, this leads to clutter very quickly, and when I do manage to be systematic sometimes one fix can lead to breaking other things. I've noticed that being able to catch errors and wrong assumptions early on is, well, let's say a Good Thing. (the opposite is hell) My guess is I have to learn to debug properly. I didn't found using the gdb with code::blocks particularly intuitive though (I had even more luck trying to use the gdb with the command line, which is quite cumbersome). And what about using exceptions, or is that more appropiate for exceptional cases as opposed to bugs? (which are still not exceptional in my case...) Any advice or opinions on how to improve the 'workflow' with better testing / debugging methods? When do you test you code and how much? (almost forget to mention I code in C++)
Advertisement
The constraints on my objects are tested whenever they are used with the assert or verify macros. This allows me to detect a large portion of the incorrect uses of a function of object by other code. The assertions are part of the program code and document clearly what the constraints on the objects are (as well as help me remember, as I am writing the code, what can be and can't be done). Don't use exceptions for error testing, this is not what they are itended for.

Then come unit testing and regression testing. I write black-box unit testing ahead of time, and only then implement the actual functions and objects it tests. This also has me eating my own dog food, which is a good idea as well, before I even write it. White-box unit testing may come afterwards as I identify weak spots (algorithms I have trouble wrapping my mind around, limit situations) and explicitely check them. Unit tests have their own code files, and are compiled separately. Regression testing allows me to check that changes do not break the behavior of the overall system. Stress is put on the system in specific situations, and the expected output (which was recorded under similar conditions the last time the test was run) is checked against the real output. If they don't match, I know something is amiss.

The usual iteration is to write the unit tests, which gives me an idea of how the module will be used. Clean up the tests. Then write the module. 15 minutes later, you should be done, so launch the tests. 5 minutes later, it should be working, and you can move on to the next module. Regularly create new regression tests (an infrastructure for this is a good idea) that use the new modules, and run all tests every so often to check that nothing is broken (do so every time you change code, as opposed to writing new one).

The above methods are there to tell me what is going wrong and where (with varying degrees of precision: asserts are more precise than unit testing which is more precise than unit testing). Then comes the debug-fest, and I've found that any debugger works wonders, be it the integrated VS.NET debugger or gdb. It just takes some time getting used to it.
ToohrVyk, thats a really clear and helpful reply, again. I will definitely start with the asserts and black box approach.

You write a whole module in 15 minutes? [wow] I feel so slow now.

About regression testing: does one (re)use the unit tests for that purpose, or is it done from 'scratch'?
The 15 minute restriction helps keeping modules small. My modules usually weigh between 50 and 200 lines of code. Since the unit testing only tests a particular, easily testable functionality, you only have to implement that functionality, usually by incorporating other small modules that do what you want. The incentive is great to rip away large bits of complexity and put them in another module so you can test them independently.

Regression testing usually involves launching large sections of the game (not only a single module), using recorded input/random seeds and logging specific function calls (rendering and sound playing, for instance) for checking against previous runs. Regression tests do not test a single module, but rather the overall behavior of a group of interacting ones. This is quite different from unit tests, which are bound to the module they test inside and out.

This topic is closed to new replies.

Advertisement