CSCI 265 notes:
- Verification and validation are concerned with assuring that a software system meets a user's
needs.
- It takes place throughout the software lifecycle with two main
objectives:
- The discovery of defects in a system.
- The assessment of whether or not the system is usable in an
operational situation.
- The two V's are not the same thing:
- Validation: are we building the right product?
- Verification: are we building the product right?
I.e. validation is ensuring we've got the right specifications,
then verification checks that we're meeting those specifications
- Dynamic vs static V&V
- dynamic validation and verification: is concerned with exercising
and observing the product behaviour (statistical testing for system
performance,
defect testing for debugging)
- static verification: is concerned with analysis of the static system
representation (inspection of documentation and source code)
GET USED TO THE IDEA OF CODE INSPECTIONS, for format, ideas,
and correctness. We'll consider formal inspection processes in about a week.
- Program testing
- Testing can reveal the presence of errors NOT their absence.
- A "good" test is one that has a high probability of revealing
an otherwise undetected error.
- A successful test is a test which discovers one or more errors.
- Tests are the only validation technique for non-functional requirements -
you cannot determine whether code runs quickly enough, reliably enough,
etc without running it.
- Program testing should be used in conjunction with static verification.
- FINDING ERRORS DURING TESTING IS A GOOD THING - or, at least,
is much better than letting the user find them later!
- Testing should be traceable to the customer's requirements -
there should be a reason behind every test you apply
- The software should be designed to be easily testable:
- the software design and the inter-relationship of system components
should be well understood
- the technical documentation should be well organized, accessible,
detailed, and accurate
- the decomposition of the software into modules or objects
should facilitate compartmentalized testing - we should be able to
easily and effectively test individual parts as well as the system
as a whole
- the software should be highly controllable, in that we can
easily generate any possible output, and easily force the program into
any desired state
- the software should be highly observable, in that we can
easily distinguish between program states, easily observe all factors
influencing the system output, and easily distinguish correct from incorrect
behavior/output
- changes to the software should be infrequent, well-controlled,
and should not invalidate existing tests
- the tests themselves should be easy to specify, easy to automate,
and easy to reproduce
- Testing and debugging
- The two are distinct processes.
- Defect testing: is confirming the presence of errors.
- Debugging: is locating and repairing these errors.
- Effective debugging involves formulating a hypothesis about program
behaviour then testing the hypothesis to find the system error:
- Locate error.
- Design error repair.
- Repair error.
- Retest program.
- Stages of testing through implementation
- Interface testing: testing the passing of parameters and
correct communication between modules and units within modules.
In "top-down" testing this is begun before the bodies of
the units are actually designed.
- Unit testing: testing of individual components. This involves
the use of drivers to substitute for routines invoking the unit under test,
and stubs to substitute for routines called by the unit under test.
- Module testing: testing collections of dependent components.
This involves the use of drivers to substitute for routines invoking
the module under test, and stubs to substitute for any called routines
which are external to the module under test.
- Sub-system testing: testing collections of modules integrated
into sub-systems, again using stubs and drivers to substitute for
any routines external to the subsystem.
- System testing: testing the complete system prior to delivery.
- Acceptance testing: testing by users to check that the system
satisfies requirements (sometimes called alpha testing).
- Sometimes these terms are combined to give component testing
(unit and module testing) and integration testing (sub-system and
system testing).
- Beta-testing is the shipment of the tested product to customers
for trials in a real working environment
- Test planning and scheduling - for complex systems, testing can
easily absorb half the development budget, so must be well planned
- Describe major phases of the testing process.
- Describe traceability of tests to requirements.
- Estimate overall schedule and resource allocation.
- Describe relationship with other project plans.
- Describe recording method for test results.
- Testing strategies
- Top-down or bottom-up.
- Stress testing.
- Back-to-back testing.
- Specialised testing strategies: e.g., thread testing for
real-time systems.
- Top-down vs bottom up testing
- Incremental testing
- Integration testing should always be incremental.
- The idea is to begin with a very simple implementation
and proceed with the following cycle:
- add a limited amount of functionality to the existing code
- carry out testing, debugging, and correction until the
existing functionality is correct
- Whichever errors are detected at a given stage are generally
in the new component (indicating an error missed during component testing)
or in the interaction between that component and existing components
(possibly a component error or an interface error).
- Stress testing
- In stress testing we exercise the system beyond its maximum
required level of performance - effectively
determining what its capabilities are.
- This may involve testing with high network loads, testing with
large data sets, testing with heavily flawed data, etc.
- Stress testing causes the failure behaviour of the software
to be invoked and hence tested - the system should never
fail catastrophically, so stress testing checks for unacceptable loss of
service or data.
- Stress testingis
particularly relevant for distributed systems which can exhibit
severe degradation as a network becomes overloaded.
- Back-to-back testing
- This involves running multiple versions of the software
on the same data and seeing if they all produce the same result - a fast
way of confirming correct or incorrect behavior in one or more of
the versions being compared
- Present the same tests to different versions of the system and
compare outputs. Different outputs imply potential problems.
- Reduces costs of examining test results; permits automatic
comparison of outputs in many cases.
- Back to back testing requires access to multiple working
versions of the software, possibly using a prototype, comparing
against older versions, comparing against versions developed for other
platforms, etc
Defect Testing
Test plans
In the test plan, as early as possible in the software development life
cycle, we are trying to identify the mechanism to be used to ensure
the customer receives a quality, tested product.
A possible test specification might be laid out something like
(see Pressman p. 504)
I. Scope of Testing
(summarizing functional, performance, and
internal design characteristics to be tested,
plus schedule constraints, completion criteria, etc)
II. Test plan
(provides the overall strategy for test integration)
A. Test phases and builds
B. Schedule
C. Overhead software
D. Environment and resources
III. Test procedures
(described separately for each phase/build)
A. Order of integration
- purpose, and modules to be tested
B. Unit tests
- description of tests and expected results
- software overhead (e.g. stubs/drivers)
C. Test environment
- special tools, techniques
- software overhead (e.g. stubs/drivers)
D. Test case data
E. Expected results
IV. Actual test results
(again supplied for each phase/build)
V. Supporting material: references, appendices etc
Static Verification
- Static verification attempts to check a program against its
specifications
without executing the program
- We address several techniques in static verification
- Program inspections
- Mathematical verification
- Static analysis tools
- Program inspections
- Formalized inspections have been part of large-scale software development
projects since the 1970s
- A small team systematically analyzes the code in an attempt to identify
possible defects
- Most inspection teams have individuals taking on the following roles:
- Author/owner - responsible for fixing defects identified during
inspection
- Inspector(s) - Finds errors/omissions/inconsistencies
- Reader - paraphrases the code or document at the inspection meeting
- Scribe - records the results of the meeting
- Moderator - manages the process and subsequently follows up on any
actions
decided by the inspection team
- Recommended preparation for the inspection process includes:
- ensuring that there is a precise specification of the code to be
inspected
- ensure that the inspection team is trained in carrying out inspections
and
is familiar with all applicable company standards
- ensure that the code under inspection is the most up-to-date,
syntactically correct
version of the code available
- preparing and maintaining checklists of likely errors/problems
- accept that static verification will increase costs during early project
stages (in hopes of reducing debugging/testing costs later)
- clarify that the inspection process is geared towards improving the
process/product quality, it is NOT an appraisal of the personnel
involved
and code inspections should NOT be a part of career reviews
- anticipate that each team member will probably spend as much time
preparing for the inspection as they will participating in the inspection
- while rates of inspection vary significantly, inspecting roughly
100 code statements per hour is not unusual
- Checklists for inspections
- the specific faults which the team needs to search for depend partially
upon what is automatically tested by the development environment:
e.g. Ada compilers will test for correct number
of parameters, C compilers will not
- Typical checks include:
- are all identifiers appropriately named
- are all variables initialized before being used
- is each variable actually used
- are all output values set before being output
- are array bounds tested
- is each conditional statement correct
- is each loop guaranteed to terminate
- is each possible case accounted for in case/switch/if-else statements
- is bracketing or begin/ends correct
- are the number, type, and order of parameters correct in each function
call
- are all links correctly managed
- is all dynamic storage allocation correctly allocated, linked, and
deallocated
- have all possible error conditions been accounted for
- Mathematical verification
- Formal verification involves proving, using mathematical arguments,
that a program meets its specifications.
- Formal verification requires that the semantics of the programming
language
are formally defined, and that the program must be formally specified in a
notation
consistent with the verification technique to be applied
- Unfortunately, most programming languages do not have formally defined
semantics, so it is usually not possible to formally prove a program correct
- Formal proofs are therefor usually applied to parts of a program,
where the program part uses only a subset of the programming language,
and where that subset of the language does have formally defined
semantics
- Static analysis tools
- there are a number of static analysis software tools (such as lint)
which scan the source
code of a program and detect possible faults and anomalies
- some of the analysis these tools carry out includes:
- control flow analysis: identifies unreachable code
- data flow analysis: identifies variables which are assigned values
that are not subsequently used, and variables which are used before being
assigned a value
- interface analysis: identifies inconsistencies in parameter
declarations and use,
including return values
- information flow analysis: identifies the set of input variables on
which each
output variable depends (not an anomaly by itself, but an aid to
identifying the possible
sources of other detected anomalies)
- path analysis: identifies all possible execution paths (again allowing
easier analysis
in other contexts)
- Clean-room approaches
- The goal of a clean-room approach is to develop zero-defect software
- The process involves three teams:
- The specification team
- The development team
- The testing team
- The approach is characterized by five aspects:
- formal specification, using a stimulus-response model
- incremental development
- structured programming, carried out through stepwise refinement of the
specifications
- static verification, using mathematically-based correctness arguments
- statistical testing, based on a predetermined operational profile