A unit test is used in software development to testing the functional parts (units) of computer programs, i.e. to check them for correct functionality. The term module test is also understood as an early test stage in which the most detailed internal components of the software are tested. See also the graphic stages of the V-model in the procedure model. According to the Software Validation & Verification Plan, unit tests are not necessary for modules with low criticality which cause little inconvenience to users in the event of errors.
Since algorithms at the unit level usually have only limited complexity and are activated via clearly defined interfaces, they can be largely fully tested with relatively few test cases. This is considered a prerequisite for the subsequent integration test level to be able to align the test cases with the integrated interaction of larger functional parts or the entire application; the module-specific detail constellations can thus be limited to samples, which drastically reduces the number of test cases required. By way of comparison, a device is only tested as a whole when the functionality of its parts is considered to be assured.
With the spread of agile software development methods and in particularly test-driven development, it has become common practice to perform unit tests as automatically as possible. For this purpose, test programs are usually written using test frameworks such as JUnit. The Test Frameworks call each test class and run their unit tests. Most test frameworks provide a graphical summary of the test results. Automated module tests have the advantage that they run easily and cost-effectively and that new bugs can be found quickly.
Pros of Unit Testing
- Errors are detected early by testing. Especially with test-driven development, the error rate is reduced by about 40%. The fact that late-discovered errors are much more expensive to fix and, if they come into production, can have fatal effects, results in a cost and risk reduction.
- In the event of a fault, it can be narrowed down much more precisely and thus found and corrected more quickly.
- The tests serve the purpose of living documentation. In combination with a meaningful naming of the objects (Clean Code), additional documentation measures can be omitted.
- Since individual modules have few possible code execution paths, much less possible combinatorial execution paths need to be considered than other tecans. Higher-level tests can focus on the most important execution paths on a random basis, significantly reducing them.
- Since only individual modules are tested, unit tests can be carried out faster and therefore more frequently (or continuously) than other test launches, often by several orders of magnitude.
- If errors are backed up with a test, it prevents that error from reoccurring.
- The error reduction results in speed advantages in development in the medium to large software projects.
- Since dependencies must be avoided to enable a unit test, the code remains changeable relatively quickly. This allows you to respond more quickly to changing requests.
- Because automatically running tests are several orders of magnitude faster than manual tests, the time required to test is significantly reduced. This allows the development stages to go through faster and shorten release cycles.
Cons of Unit Testing
- When implementing new functionality, not only does the function need to be implemented, but the associated tests must also be prepared/defined. This results in often multiple implementation costs.
- Changes require you to customize not only the changed functionalities but also the associated tests. Testing is therefore often a hindrance to the development of prototypes, where the codebase changes rapidly.
- Because the functionality is used by the tests, IDEs make it harder to see whether the functionality is no longer used elsewhere and can therefore be removed.
- If the tests have interdependencies (e.B. by common test data), individual changes to the code base can affect a variety of tests, which increases the amount of change effort exponentially with the size of the codebase.