A module test (including English unit test as a unit test , or as components of test hereinafter) is used in the software development applied to the functional components ( units ) of computer programs to test , i. i.e. to check that they are working correctly.
The term module test is also understood as an early test stage in which the inner, most detailed components of the software are tested. See also the graphic stages of the V-model in the process model (according to Barry Boehm ). According to the Software Validation & Verification Plan , module tests are only not necessary for modules with low criticality (which cause the user little inconvenience in the event of errors).
Classification in the test process
Since algorithms at the unit level usually have only a limited complexity and are activated via clearly defined interfaces, they can be largely fully tested with relatively few test cases . This is a prerequisite for the subsequent test level integration test in order to be able to align the test cases there with the integrated interaction of larger functional parts or the entire application; the module-specific detailed constellations can thus be limited to random samples, which drastically reduces the number of test cases required.
For comparison: A device is only tested as a whole when the functionality of its individual parts is considered to be assured.
Test case definition procedure
Module tests are part of the white box tests . This means that the source code to be tested is known when the test cases are defined. The specification of the software is only used to determine the target results. In principle, all source code parts must be executed at least once. Instruction coverage , branch coverage or path coverage can help determine which test cases are at least theoretically required for this (see control flow- oriented test procedures ). In practice, attempts are generally made to achieve the set coverage target with as few test cases as possible, since all module tests also have to be continuously updated.
Procedure for creating unit tests
Usually, all module tests are based on a uniform basic structure. First (1) an initial state is initialized, then (2) the operation to be tested is carried out and finally (3) the actual result is compared with a setpoint value derived from the specification. For these comparisons, the test frameworks
assertmethods (German: determine, insure) are available.
Properties of unit tests
Isolation of test objects
Module tests test a module in isolation, i.e. H. largely without interaction with other modules. For this reason, other modules or external components such as a database , files , backend systems or subroutines must or can be simulated by auxiliary objects during module tests , as far as the module to be tested ( test item or test object) requires this.
Auxiliary objects that can be used for this purpose can essentially be distinguished according to
- whether a to be invoked module replace (Sample is the calling module; the replacement object , the stub ' referred to),
- whether they replace the call (the environment) of a module / subroutine to be tested (the test item is the subroutine, the routine that simulates the call is called the 'driver').
How completely the auxiliary routine maps the behavior of the original, for example in plausibility checks or in the return of response codes, must be taken into account by means of a corresponding test case design. Particularly in object-oriented programming languages, further, more detailed categories of auxiliary objects can be distinguished in this regard, see mock object .
Such auxiliary objects are z. B. implemented as a substitute and provided by means of inversion of control . A module can usually be tested more easily than if all modules are already integrated, since in this case the dependency of the individual modules would have to be taken into account and taken into account in the test handling. Such isolated module tests are also possible when other components that are actually required for the test are not yet available.
Complete tests with all components in their original version are the subject of the integration and system tests that take place later - whereby errors not recognized in the module test (e.g. due to identical false assumptions for the test object and the auxiliary routine) should be discovered.
Test of the contract and not the algorithms
According to the design-by-contract principle, module tests do not test the internals of a method, if possible, but only its external effects (return values, outputs, changes in status, assurances). If the internal details of the method are checked (this is known as white box testing), the test could fail even though the external effects have not changed. Therefore, so-called black box testing is usually recommended, in which one restricts oneself to checking the external effects.
Automated module tests
With the spread of agile software development methods and especially test-driven development , it has become common practice to carry out module tests as automatically as possible. For this purpose, test programs are usually written with the help of test frameworks such as JUnit . The individual test classes are called via the test frameworks and their unit tests are carried out. Most test frameworks provide a graphical summary of the test results.
Automated module tests have the advantage that they can be carried out easily and inexpensively and that new program errors can be found quickly.
- Errors are detected early through tests. Especially with test-driven development , the error rate is reduced by approx. 40%. The fact that errors discovered late are much more expensive to fix and, if they come into production, can have fatal consequences, results in a reduction in costs and risk.
- In the event of an error, it can be narrowed down much more precisely and thus found and eliminated 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 only have a few possible code execution paths, far fewer possible combinatorial execution paths have to be taken into account than with other test types. Higher-level tests can be randomly concentrated on the most important execution paths and thus significantly reduced.
- Since only individual modules are tested, module tests can be carried out faster and therefore more often (or continuously) than other types of test, often by several orders of magnitude.
- If errors are secured with a test, this error is prevented from occurring again.
- The reduction in errors results in speed advantages in development in medium to large software projects.
- Since dependencies must be avoided in order to enable a module test, the code can be changed relatively quickly. This means that it is possible to react more quickly to changing requirements.
- Since tests that run automatically are several orders of magnitude faster than manual tests, the time required for testing is significantly reduced. This allows development stages to go through faster and the release cycles to be shortened.
- When implementing new functionality, not only must the function be implemented, but the associated tests must also be prepared / defined. This often results in a multiple implementation effort.
- In the event of changes , not only the changed functionalities but also the associated tests have to be adapted. Testing is therefore often a hindrance, especially when developing prototypes, where the code base changes quickly.
- As the functionality is used by the tests, it is more difficult to see in IDEs whether a functionality is no longer being used and can therefore be removed.
- If the tests have interdependencies (e.g. due to shared test data), individual changes to the code base can influence a large number of tests, which increases the cost of changes exponentially with the size of the code base.
Module tests (like any test) cannot guarantee or prove that the tested module is free from defects, but only support it. The limits of module tests are necessarily that only those errors can be found that the tests used are capable of discovering. A software component that tests “green” is therefore not necessarily free of errors.
The characteristic of code to test “green”, and certainly also the desire for this result, could actually (unconsciously) only result in testing until all tests are “green”. Treating modules that do not fail module tests as error-free is a frequent fallacy in practice in test-driven development.
In order to achieve sufficient test coverage , it may be worthwhile. You may need to apply refactoring measures before creating the test cases . Doing this only after unit tests have been completed (for the old code) would (like any change in the code) involve new risk of errors and therefore require repeated testing.
If - as usual - the author of the module tests is identical to the author of the modules, errors in the implementation can also appear in the test and not be revealed. If it is the same person, this is not excluded by the fact that the tests are developed first, since both the intended functioning of the code and its future shape can already be present in the thinking of the test author and later code author. This can be intercepted in extreme programming by "test ping-pong", as developers take turns implementing the functionality and the tests.
During the development of module tests, test cases can arise that do not or only partially correspond to the objectives and character of module tests. As with programming, there are anti-patterns for the development of module tests , which should be avoided if possible.
- Paul Hamill: Unit Test Frameworks. (A Language Independent Overview) . O'Reilly Media, Beijing et al. a. 2004, ISBN 0-596-00689-6 (English).
- Gerard Meszaros: xUnit Test Patterns. Refactoring test code . Addison-Wesley, Upper Saddle River NJ u. a. 2007, ISBN 978-0-13-149505-0 (English).
- Andreas Spillner, Tilo Linz: Basic knowledge of software testing. Training and further education to become a Certified Tester. Foundation level according to the ISTQB standard . 4th, revised and updated edition. dpunkt-Verlag, Heidelberg 2010, ISBN 978-3-89864-642-0 .
- Link catalog on the topic of unit testing at curlie.org (formerly DMOZ ) (English)
- Introduction to the principles of unit testing
- Development of module tests with examples , author Markus Lenger, in: Informatik Aktuell (magazine)
- Articles about unit testing in Java (English)