|
With the description of typical testing in the
preceding section, it would seem that nothing else should be necessary.
And if that testing is expensive enough, why should management consider
spending even more money on testing?
The answer is accuracy. Typical testing allows
significant parts of a program to go untested. Typical testing is like
single entry bookkeeping, there is no way to check that it was done as
well as you think it was done. If the business cost of an undetected
fault is sufficiently high, then the accuracy of typical testing may be
insufficient to cover the business risk. If it does make business sense
to extend the accuracy of testing, then there are several techniques
that can be used to do so in addition to simply doing more typical
testing, and these are discussed below. Conversely, if the business cost
of an undetected fault is acceptable, then no further effort should
be expended.
Typical testing usually covers only positive
cases. In other words, we enter this correct transaction data and we
see the same result in the migrated program as in the original program.
Professional testing will also cover negative
cases. We put in every conceivable variant of an incorrect transaction,
and ensure that it is properly rejected, from both the original and
migrated versions. This is particularly evident in testing online
programs, where each field should have both no entry and incorrect data
submitted for processing. Where cross-field editing is done, each
combination should be permuted across the affected fields. Note that in
executing negative testing, it frequently will be the case that faults
in the original programs will be uncovered.
If typical testing is like single entry bookkeeping, then using coverage
analysis in your testing is like double entry bookkeeping - you have a
method to use to check whether you have actually tested what you think
you have tested. An example excerpt from a coverage analysis report
follows:
|
1000-INITIALIZATION.
PERFORM 1100-GET-TODAYS-DATE
Exec
THRU 1100-EXIT.
Exec
INITIALIZE T-ZONE-TABLE.
Exec
OPEN INPUT CARDIN.
Exec
MOVE 'N' TO S-CARDIN-EOF.
Exec
MOVE +0
TO A-RULE-TOT.
Exec
PERFORM 1200-READ-CARDIN
THRU 1200-EXIT
Exec
UNTIL S-CARDIN-EOF = 'Y'.
Exec
CLOSE CARDIN.
Exec
IF W-CARD-1-BATCH-NBR >
ZEROES
Exec
MOVE W-CARD-1-BATCH-NBR
TO PARC8703-BATCH-NBR
=No=
PERFORM 1300-MODIFY-BATCH THRU 1300-EXIT
=No=
END-IF.
=No=
IF W-CARD-1-BATCH-NBR-8 >
ZEROES
Exec
MOVE W-CARD-1-BATCH-NBR-8
TO PARC8703-BATCH-NBR
=No=
PERFORM 1300-MODIFY-BATCH THRU 1300-EXIT
=No=
END-IF.
=No=
PERFORM 1400-BIND-AND-READY THRU
1400-EXIT.
Exec
PERFORM 1500-CONVERT-DATES
THRU 1500-EXIT.
Exec
DISPLAY ' '.
Exec
1000-EXIT.
Exec
EXIT.
Exec
|
This report shows exactly which lines of code in this section of the
program have been executed (“Exec” in the example) and which not (“=No=”
in the example). This shows us that the input record in the CARDIN file
did not contain a case where "W-CARD-1-BATCH-NBR
> ZEROES” is true, so we know we need to re-execute this
program with that field containing a non-zero value in order to exercise
the program code in paragraphs
1300-MODIFY-BATCH THRU 1300‑EXIT.This form of coverage analysis does not ensure that
all lines of code will be executed. It only provides a way to measure
the amount of coverage, and allows the knowledgeable application
specialist to decide whether or not the coverage is sufficient. His or
her judgment might be incorrect, saying on the one hand that additional
coverage is necessary when it is not (resulting in higher than necessary
costs) or on the other hand that additional coverage is not necessary
when it is (leading to a latent fault not being discovered until
production testing when it is much more expensive to correct). However,
it does provide checks and balances on the testing process.
There are other forms of coverage analysis besides
this report showing lines of code coverage, which is also known as
branch and path coverage. More sophisticated analyses can determine
whether all permutations of branch paths have been taken, known as
logical test path coverage analysis. Other analyses can determine
whether arithmetic statements have been executed with a full range of
values. And there are even more obscure situations that can be
measured. The type of coverage and the degree of coverage are suitable
topics for a risk management discussion during migration project
planning, but typically branch and path coverage will be sufficient for
all but a very few cases.
Reviewing coverage analysis reports can be time
consuming, and requires the attention of application knowledgeable
people whose time is in heavy demand. These report reviews are
difficult to relegate to contract or staff personnel who do not have
detailed knowledge of the application. However, it is possible to
optimize this and other aspects of project testing, which we will
discuss in the next sections.
It is possible to say that certain constructs that
occur within a given program or within the entire suite of programs
should always be covered. For example, if the migration project is
going to be replacing indexed file access or an older database with a
relational database management system, then all of the unique accesses
of each file from the old data stores should be tested at least once
amongst the coverage reports. Or, programs that are updating the
database should test all arithmetic constructs. Et cetera.
These kind of construct coverage rules can be
derived during project planning, and can be applied before submitting a
final set of coverage analysis reports to subject matter experts. These
rules can be used to create a list of constructs that must be covered,
and an analysis report created showing which mandatory constructs have
not been covered at least once.
Note that the migration methodology impinges on
testing at this point. If the migration is being conducted using a
fully automated process, then a single instance of each construct may be
sufficient to prove the transformation of that construct correct. If,
however, the process is only partially automated, or if it is wholly
manual, then there is the opportunity for the same construct to be
transformed in different ways in different programs. In this case,
construct coverage analysis may be of limited if any value.
Some programs require more testing than other
programs, but is there a way to determine which ones those are?
Certainly, programs with more complex logic in the expression of their
business rules will have more branch paths over which to ensure
coverage. However, it can also be argued that fairly straightforward
reporting programs do not need the analytical scrutiny of primary
transaction processing program.
It is possible to process program sources and
derive various metrics regarding their complexity. Of the many such
metrics, perhaps the best known is McCabe’s Cyclomatic Complexity.
If we derive this or an alternative metric for the entire library of
sources under consideration, then we can apply the greatest testing to
the most complex programs, and proportionally less testing for the less
complex programs.
Risk optimized
testing says that the most testing should be applied to the programs
where a fault will create the greatest negative impact. Arguably, a
report program need not have much more testing than a correctness test
of the output, matching control totals and perhaps checking the
sequencing and number of pages. A program that extracts data for
analysis or reporting by other programs probably needs more testing
since an error in that program could propagate to other downstream
programs. And a program that updates the primary database should
receive the most testing attention, with a careful analysis of the
coverage reports. Such a risk index can be derived fairly simply and
can be combined with the complexity analysis discussed above. The exact
algorithm for risk optimized testing will be unique to each project, but
if the algorithm is derived as part of discussions during project
planning it offers the opportunity for increased accuracy while
controlling testing costs.
|