|
||||||
Excerpt from Special Edition: Computer Validation III
Software Structural Testing Methods By George N. Brower Analex Corporation
Definition of Software Structural Testing Software structural testing is meant to challenge the decisions made by the program with test cases based on the structure and logic of the design and source code. Complete structural testing exercises the program’s data structures (such as configuration tables) and its control and procedural logic at the test levels discussed below.
Unit-Level Structural Testing Figure 2 illustrates a typical configuration for a structural unit test. The unit is compiled and linked with a driver and stubs, as needed. The driver is a substitute for any actual unit that will eventually call the unit-under-test, and if the driver passes data to the unit-under-test, it is set up to pass test case variable values such as maximum, minimum, and other nominal and “stress-test” values. The stubs are substitutes for any units called by the unit-under-test. As with the driver, if the stubs return data to the unit-under-test, they also pass “stress test” and nominal data values, as appropriate. The interface of the drivers and stubs, including their names, are the same as the true units’ interfaces, allowing the set of units to be linked without altering the unit-under-test. Unit-level structural tests can be conducted on the actual target hardware, on an emulator or simulator of the actual hardware, or, if the situation requires, on a totally different processor. The latter case may occur, e.g., if the actual hardware has no provision for determining the results of a unit’s tests, but where the code is written in a higher order language. Thus, the higher order source code (such as C or C++) can be compiled and linked to run on another computer that supports reading the test results where the target computer (for example, an embedded microprocessor) could not support the tests. The Environment for Both Integration-Level and System-Level Structural Tests It is best to set up the integration and system structural tests using the actual hardware and environment to the extent practical. There are several reasons for this, but the two most significant are (a) the software may have subtle conditions, both good and bad, that will only show up when running on the actual hardware, and (b) the final computerized system, including the intended hardware and software, must be qualified running on that hardware, and the structural tests should advance the software development towards that end. However, there are also good and sufficient reasons to perform structural tests partially or wholly in a simulated environment. In considering establishing simulation capabilities, the two most common configurations are to either emulate the computer and simulate the environment (used most often when the actual computer is an embedded microprocessor and it is difficult to stimulate known inputs and/or read the outputs of a test) or to simulate both the computer and the environment (used, e.g., if an emulator of the target computer is not available). The principal advantages, then, in using a simulation of the environment and, at times, the computer include the following: (a) the ability to set up absolutely known input values, such that the results can be predetermined to establish the acceptance criteria of each test; (b) a simulator makes it easy to establish inputs that are over, under, and at the exact limits of critical data values; (c) it is easy to set up illegal inputs to test all error and failure conditions; and, finally, (d) the results of each test can be readily seen. Integration-Level Structural Testing Integration structural testing combines functionally cohesive units of verified code (which includes unit-level structurally tested code) by compiling and/or assembling and linking the code, along with any drivers and stubs needed. The structure is then loaded into the actual or simulated environment for execution. This allows the tester to focus on that one functional package to confirm its correct operation, including all internal and external interfaces. Following completion of each functional package’s test, the next functional package may be either separately tested or added to (i.e., linked with) the previously tested package(s). Regression testing (i.e., running a selected subset of previous, successfully run test cases) must be performed on the previously tested packages to confirm they are not adversely affected by the newly introduced functional package. The Incremental Approach The incremental approach to integration-level structural tests is the best for software developers (as opposed to third party, validation testers – see below), especially if the program is large or complex. In this approach, selected small, functionally cohesive portions of the software are compiled, linked, and tested. This approach is used regardless of the software life cycle development method being employed, including any of the following three methods. In the waterfall method, all of the requirements are developed, then the design is completed, and, finally, selected “threads” are coded and structurally tested. In the spiral method, a major element of the software system is discussed and then the requirements, design, and code are developed, and the element’s structural test is performed prior to going on to discuss and develop the next major element. Finally, in the incremental software development method, all of the specifications and requirements may be developed, but the design and implementation are developed one function at a time.
|
||||||
|