Pretty much everyone is aware of how software is produced. A person or group designs a program, picks (or are assigned) a language, and codes it. But not everyone knows what happens next. There is, or at least should be, some form of testing to verify that the program ‘works’.
In fact, there often should be multiple types of testing. The first type of test, perhaps even before all the code is complete, is done usually by the person doing the coding. This test is based on how the program is coded; the format is ‘white box’. The goal is to exercise as many of the paths and branches in the code as is practical. Why is this usually done by the coder? Because it is unlikely anyone else will be as familiar with how it is coded. And because it would be incredibly unwise to move the code anywhere else without ensuring that the coder has some confidence the code is viable.
This test is often called ‘Unit Test’.
Unit test tends to be informal and highly integrated into the coding. It often has no structure, no planning and no reporting. By definition, it requires no documentation beyond what the coder has to generate the code from. Because the person who is finding problems is the person who is writing the code, and the method of testing often clearly indicatess where the problem is, fixes are easily implemented and the need for bug tracking is reduced or eliminated.
Choosing what to test is moderately easy; remember, the goal is to verify as many code paths as practical and take as many possible branches as is practical. It can be helpful to use a paper printout of the code and highlighters to figure out which paths to follow first, and during testing, which paths have already been verified.
To validate a path, you set up the inputs or input sequences to theoretically access the path, and then make sure the path is indeed followed (without hangs, crashes, undesired deviation from the path or obvious unintended results from that path). To validate a branch, you use your inputs to force every option of the branch. In particular, you are looking for the effects resulting from ‘unterminated’ branches. The simplest of these would be ‘if x = 0 then A = 5’. What happens if x is not 0? Is ‘A’ guaranteed to be initialized somewhere else before it will be used later on?
Many programs are written as a collection of ‘modules’. Unit test is at the module level, using tools and/or ‘scaffolding’ to provide the inputs and interfaces, and view the outputs. Not only that, but a common testing methodology is to stick temporary ‘message’ commands into the code, to verify when/if the code gets there and view the values of variables of interest.
Often the coder will venture outside of just testing paths and branches, and actually try out the program or section of program (using ‘black box’ methodology). Although the goal of this testing may be the same as later tests, this is still part of the coding process, and can follow the informal nature associated with Unit tests.
As you can see, it is important that coders be at least as good at ‘Unit Testing’ as they are at coding. One who cannot or will not Unit test, would seem to not really be a ‘coder’. Or at least not a complete coder.
In short, unit test is a critical part of the coding process. The ‘output’ of this test is the output of the coding process, code which is ready for a more formal and more functional test.