Wafer testing is a step performed during semiconductor device fabrication. During this step, performed before a wafer is sent to die preparation, all individual integrated circuits that are present on the wafer are tested for functional defects by applying special test patterns to it. The wafer testing is performed by a piece of test equipment called a prober, and the process is sometimes referred to as probe test or wafer sort.
When all test patterns pass for a specific die, its position is remembered for later use during IC packaging. A die that does not pass all test patterns is usually considered to be faulty and thrown away. Non-passing circuits are typically marked with a small dot of paint in the middle of the die.
In some very specific cases, a die that passes some but not all test patterns can still be used as a product, typically with limited functionality. The most common example for this is a microprocessor for which only one part of the on-die cache memory is functional. In this case, the processor can sometimes still be sold as a lower cost part with a smaller amount of memory and thus lower performance.
The contents of all test patterns and the sequence by which they are applied to an integrated circuit is called the test program.
After IC packaging, a packaged chip will be tested again during IC testing phase, usually with the same or very similar test patterns. For this reason, one could think that wafer testing is an unnecessary, redundant step. In reality this is not the case, since the removal of defect dies saves the considerable cost of packaging faulty devices. However, when the production yield is so high that wafer testing is more expensive than the packaging cost of defect devices. In this case, the wafer testing step can be skipped altogether and dies will undergo blind assembly.
The granularity of the first tests was too great to be able to move quickly; so once they were in place the first thing to do was to break out the lower level code that we wanted to test and use the initial tests to make sure we hadn't changed any behaviour.
Most of this was done using pair-programming; one of us to introduce tests to the code as quickly as possible and one who knew the existing code and knew how the system hung together.
The next step is to fill out the tests and refactor the code as required to remove some of the 'fluff', make the code simpler and easier to understand.