Page 235 -
P. 235

218   Chapter 8   Software testing


                                       operate at different speeds. Unless particular care is taken in the interface design,
                                       the consumer can access out-of-date information because the producer of the
                                       information has not updated the shared interface information.

                                       Testing for interface defects is difficult because some interface faults may only
                                    manifest themselves under unusual conditions. For example, say an object imple-
                                    ments a queue as a fixed-length data structure. A calling object may assume that the
                                    queue is implemented as an infinite data structure and may not check for queue over-
                                    flow when an item is entered. This condition can only be detected during testing by
                                    designing test cases that force the queue to overflow and cause that overflow to cor-
                                    rupt the object behavior in some detectable way.
                                       A further problem may arise because of interactions between faults in different
                                    modules or objects. Faults in one object may only be detected when some other object
                                    behaves in an unexpected way. For example, an object may call another object to
                                    receive some service and assume that the response is correct. If the called service is
                                    faulty in some way, the returned value may be valid but incorrect. This is not immedi-
                                    ately detected but only becomes obvious when some later computation goes wrong.
                                       Some general guidelines for interface testing are:


                                    1.  Examine the code to be tested and explicitly list each call to an external compo-
                                        nent. Design a set of tests in which the values of the parameters to the external
                                        components are at the extreme ends of their ranges. These extreme values are
                                        most likely to reveal interface inconsistencies.

                                    2.  Where pointers are passed across an interface, always test the interface with null
                                        pointer parameters.

                                    3.  Where a component is called through a procedural interface, design tests that
                                        deliberately cause the component to fail. Differing failure assumptions are one
                                        of the most common specification misunderstandings.
                                    4.  Use stress testing in message passing systems. This means that you should
                                        design tests that generate many more messages than are likely to occur in prac-
                                        tice. This is an effective way of revealing timing problems.
                                    5.  Where several components interact through shared memory, design tests that
                                        vary the order in which these components are activated. These tests may reveal
                                        implicit assumptions made by the programmer about the order in which the
                                        shared data is produced and consumed.


                                       Inspections and reviews can sometimes be more cost effective than testing for
                                    discovering interface errors. Inspections can concentrate on component interfaces
                                    and questions about the assumed interface behavior asked during the inspection
                                    process. A strongly typed language such as Java allows many interface errors to be
                                    trapped by the compiler. Static analyzers (see Chapter 15) can detect a wide range
                                    of interface errors.
   230   231   232   233   234   235   236   237   238   239   240