Basic Embedded Firmware testing essentials and Software Test plan
Some of these are more idiot-checks of the code than actual testing procedures, but they're good to do anyway.


Make sure you have good specs. If you have clear specs for every possible variable that matters for your project, testing should just be a matter of comparing against the spec. It never is, but it's a nice goal. One thing that sometimes gets left out of specs is response time. If your system does as its told, but it takes a second instead of a millisecond, you still don't have a good system.
Test each individual piece of the firmware separately. Make sure the
A/D converters work, make sure the lights turn on as commanded, make
sure each input works, make sure each output works, make sure the
timers work. Then start worrying about how it all works together.
It's almost certain the firmware won't work on the first pass, and
you'll have to break it down into pieces anyway. Best to start there.
Turn the board on and off many dozens times and make sure everything
starts up properly on a consistent basis. Probably a good idea to
watch all the power rails on a scope and make sure all the regulators
start up. Do this with every possible combination of inputs and power
supplies. This tests both your hardware and your software.
Expose the unit to EMI/RFI noise. I typically take an AC hipot tester
and short it to itself to generate high-voltage low-current sparks.
Wreaks havoc on circuits lacking noise immunity. (Plus, dragging the
sparks along the chassis makes you feel like a tiny version of
Emperor Palpatine. But maybe that's just me.) This tests both your
hardware and your software.
Look for all possible cases of division or modulus by a variable.
Make sure you can never, ever divide or mod by a variable that could
possibly be set to zero.
Look for all pointers, and make sure that none of the thousand things
you can do wrong with pointers can possibly happen.
Look for all arrays, and make sure you can never run off the end of
the array.
Look for all instances of what you intended to be comparison (==) and
make sure they're not assignment (=). A helpful regexp for this would
be: (.+ = .+)
Look for any occasions of EEPROM writes, and make sure to thoroughly
test those cases. EEPROM is slow, so multiple EEPROM writes in
series might slow down other time-critical processes. This could
simply trip your watchdog timer and cause a reset, or (in the case of
a switching power supply) this could cause an explosion because your
outputs didn't get updated properly.
If you're using any interrupts at all, try not to unless absolutely
necessary. They increase the number of possible unexpected code
interactions dramatically. If you have to use interrupts, consider
what happens if the interrupt happens at every possible point in the
execution of your program. Also, consider every possible nesting of
interrupts, or just disable nested interrupts so you don't have to
worry about it.