Testing, in general, cannot be expected to catch every error in the program.
The same is true for unit testing. By definition, it only tests the
functionality of the units themselves. Therefore, it may not catch integration
errors, performance problems, or other system-wide issues. Unit testing is more
effective if it is used in conjunction with other software testing activities.
Like all forms of software testing, unit tests can only show the presence of
errors; it cannot show the absence of errors.
Software testing is a combinatorial problem. For example, every boolean
decision statement requires at least two tests: one with an outcome of "true"
and one with an outcome of "false". As a result, for every line of code written,
programmers often need 3 to 5 lines of test code. Therefore, it is unrealistic
to test all possible input combinations for any non-trivial piece of software
without an automated characterization test generation tool such as JUnit Factory
used with Java code or many of the tools listed in List of unit testing
To obtain the intended benefits from unit testing, a rigorous sense of
discipline is needed throughout the software development process. It is
essential to keep careful records, not only of the tests that have been
performed, but also of all changes that have been made to the source code of
this or any other unit in the software. Use of a version control system is
essential. If a later version of the unit fails a particular test that it had
previously passed, the version-control software can provide a list of the source
code changes (if any) that have been applied to the unit since that time.
It is also essential to implement a sustainable process for ensuring that
test case failures are reviewed daily and addressed immediately. If such a
process is not implemented and ingrained into the team's workflow, the
application will evolve out of sync with the unit test suite—- increasing false
positives and reducing the effectiveness of the test suite.