home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / software / 3011 < prev    next >
Encoding:
Internet Message Format  |  1992-07-30  |  10.1 KB

  1. Xref: sparky comp.software-eng:3011 comp.object:3069
  2. Newsgroups: comp.software-eng,comp.object
  3. Path: sparky!uunet!destroyer!gumby!wupost!m.cs.uiuc.edu!marick
  4. From: marick@m.cs.uiuc.edu (Brian Marick)
  5. Subject: Testing Software that Reuses (long)
  6. Message-ID: <1992Jul30.200315.11868@m.cs.uiuc.edu>
  7. Organization: University of Illinois, Dept. of Comp. Sci., Urbana, IL
  8. Date: Thu, 30 Jul 1992 20:03:15 GMT
  9. Lines: 225
  10.  
  11.  
  12.                       TESTING SOFTWARE THAT REUSES[1]
  13.                                Brian Marick
  14.  
  15. The producer of reusable software provides a part of the product built by a
  16. software developer (here called the "consumer").  The producer tests this
  17. reusable part, but the consumer must test the rest.  This note addresses
  18. the question of how the producer can help the consumer test.
  19.  
  20. The producer should provide a catalog of reusable test conditions derived
  21. from likely misuses of the reused software.  The consumer then designs test
  22. cases by combining the producer's test conditions with test conditions
  23. derived from the rest of the product.
  24.  
  25. But there's more to testing than designing tests - there's also measuring
  26. whether they do what they're supposed to do.  Coverage tools, which record
  27. measures like branch coverage, fill this role.  They should be extended so
  28. that producers can provide modules that measure how well potential misuses
  29. have been tested.  An existing freely distributable coverage tool will be
  30. so extended.
  31.  
  32. ____________________
  33.    [1] Technical Note 2, Testing Foundations, Champaign, IL 61820, 1992.
  34.  
  35.  
  36. 1.  The Argument
  37.  
  38. (1)  Conditions to test can be found by examining past programmer errors.
  39.  
  40. (2)  Often, errors are due to misuse of an abstraction.
  41.  
  42. (3)  Sometimes, the abstraction is implemented as reusable software.
  43.  
  44. (4)  Its producer should provide the error history in a form useful for
  45.      testing.
  46.  
  47. (5)  The consumer can use this information when building test cases.
  48.  
  49. (6)  A coverage tool can measure how thoroughly the consumer's tests have
  50.      probed likely misuses.
  51.  
  52. 2.  Test Design
  53.  
  54. Test design occurs in two stages, be they implicit or explicit.  In the
  55. first stage, test conditions are created.  A test condition is a require-
  56. ment that at least one test case must satisfy.
  57.  
  58. Examples:
  59.         Argument A is negative.
  60.         Argument A is 0.
  61.         Arguments A and B are equal.
  62.  
  63. In the second stage, the test conditions are combined into test cases which
  64. precisely describe the inputs to the program and its expected results.
  65.  
  66. Example:
  67.         A=-1, B=-1
  68.         Expected value:  13
  69.  
  70. This test satisfies two of the test conditions.  The rules by which test
  71. conditions are combined into test cases are irrelevant to the argument of
  72. this note.
  73.  
  74. Where do the test conditions come from?  Most obviously, they come from the
  75. specification, the description of what the program is to do.  For example,
  76. if we're testing the implementation of a memory allocator, malloc(amount),
  77. we might get these test conditions:
  78.  
  79.         amount is negative
  80.         amount memory is available.
  81.         Not enough memory is available.
  82.  
  83. In this case, there's a test condition to see if the program handles
  84. invalid inputs correctly and two test conditions for the two kinds of
  85. return values.
  86.  
  87. Test conditions also come from an understanding of the types of errors the
  88. programmer likely made while writing the program.  Specifications and pro-
  89. grams are built from cliches [Rich90], such as "searching a list", "sorting
  90. a list", "decomposing a pathname into a directory and a file", "hash
  91. tables", "strings" (null terminated character arrays), and so on.  Notice
  92. that both operations and data types can be cliches.  Programmers often make
  93. cliched errors when implementing or using cliches [Johnson83].  Thus, you
  94. can create a catalog of test conditions, indexed by cliche.  One such cata-
  95. log is [Marick92].
  96.  
  97. There are two ways cliches may be manifest in programs:
  98.  
  99. (1)  They may be implemented inline.  For example, a searching cliche may
  100.      be implemented as a loop over a vector.
  101.  
  102. (2)  They may be reusable code.  The searching cliche may be implemented as
  103.      a call to a subroutine named bsearch() .
  104.  
  105. The test conditions for a cliche-using program depend on the manifestation.
  106. If the cliche is implemented inline, you must test that implementation.
  107. For a vector search loop, you'll use a test condition that probes for off-
  108. by-one errors: "element found in last position".  But if the search is a
  109. call to a well-tested subroutine, that test condition would likely be use-
  110. less.  Instead, you would restrict your attention to plausible errors in
  111. the program's use of the cliche -- faults where bsearch is called
  112. correctly, but the program fails to handle the result properly.  Here, a
  113. test condition might be "element not found", since programmers sometimes
  114. fail to think about that possibility.  Another example would be testing
  115. uses of the write() routine with "write fails", since programs that assume
  116. writes always succeed abound.
  117.  
  118. Of course, not all reusable subroutines implement cliches, but all reusable
  119. code can generate the same sort of test conditions, test conditions that
  120. probe likely misuses.  In the absence of more information, some general
  121. rules are:
  122.  
  123. (1)  A test condition for each error return.
  124.  
  125. (2)  A test condition for each distinct type of "normal return".  For exam-
  126.      ple, if a routine returns five status codes, the calling program isn't
  127.      well tested unless it has shown that it can handle all five possibili-
  128.      ties.
  129.  
  130. But there can also be test conditions particular to a reused routine or
  131. datatype.  For example, suppose a collection that can grow and shrink is
  132. provided as a datatype.  However, the user must reinitialize the collection
  133. whenever the last element is removed.  Programmers will surely often forget
  134. the reinitialization; this likely error can be captured in a test condition
  135. like "an element is removed from a single-element collection, then a new
  136. element is added".
  137.  
  138. Henceforth, these test conditions will be called producer test conditions.
  139. Consumers find these producer test conditions, since they make the common
  140. mistakes.  The people best suited for circulating this information to all
  141. consumers are the producers.  (Of course, in this particular case, they
  142. would also want to rework the design of the datatype to eliminate the cause
  143. of the common error, but this cannot always be done.  Some abstractions are
  144. simply inherently complicated.)
  145.  
  146. Along with reusable software, vendors should sell catalogs of producer test
  147. conditions.  These are used in the same way as, and in conjunction with,
  148. the general-purpose cliche catalog mentioned earlier.  For example, if a
  149. consumer is writing software that uses a stream of input records to modify
  150. a collection, the "empty, then add" producer test condition can be combined
  151. with generic stream test conditions to produce good test cases for that
  152. software.
  153.  
  154. 3.  Test Coverage
  155.  
  156. I won't discuss coverage in detail.  If you want to learn about coverage,
  157. get a copy of my freely available test coverage tool, GCT.  It's available
  158. by anonymous FTP from cs.uiuc.edu.  Start by fetching pub/testing/GCT.README.
  159.  
  160. GCT is used in three phases.
  161.  
  162. (1)  The program is instrumented by adding code to check whether coverage
  163.      conditions are satisfied.  Coverage conditions are test conditions
  164.      derived mechanically from the code.  Example: one coverage condition
  165.      might require that an IF on line 256 be taken in the TRUE direction,
  166.      while another would require that the < on line 397 be evaluated with
  167.      its left-hand side equal to its right-hand side.  (This boundary con-
  168.      dition helps discover off-by-one errors.)
  169.  
  170. (2)  At runtime, the program executes and updates a log of which coverage
  171.      conditions have been satisfied.
  172.  
  173. (3)  After the program runs, reporting tools produce output that looks like
  174.      this:
  175.  
  176.      "lc.c", line 256: if was taken TRUE 0, FALSE 11 times.
  177.      "lc.c", line 397: operator < might be <=.
  178.  
  179. What good is that output?  In some cases, it points to weaknesses in test
  180. design.  For example, the second line may be a symptom of forgetting to
  181. test boundaries.  The first line may point to an untested feature.  In
  182. other cases, coverage points to mistakes in implementation, where your
  183. tests don't test what you thought they did.  (This happens a lot.)
  184.  
  185. The tester of software that reuses would find coverage more useful if it
  186. were derived from the reused software.  Suppose the tester forgot about the
  187. "last element removed and new one added" test condition.  Or suppose it was
  188. tested, but the test's input was handled by special-case code that never
  189. exercised the collection at all.  Conventional coverage very well might
  190. miss the omission.  What the tester wants is a coverage report that looks
  191. like this:
  192.  
  193. "lc.c", line 218: collection.add never applied to reinitialized collection.
  194. "lc.c", line 256: if was taken TRUE 0, FALSE 11 times.
  195. "lc.c", line 397: operator < might be <=.
  196. "lc.c", line 403: bsearch never failed.
  197.  
  198. The last condition prompts us to write a test to detect omitted error-
  199. handling code.  Branch coverage, for instance, would not tell us we need to
  200. write such a test - it can't generate a coverage condition for an IF state-
  201. ment that ought to be there but isn't.  Such faults of omission are common
  202. in fielded systems [Glass81].
  203.  
  204. To allow such coverage, a producer must provide two things:
  205.  
  206. (1)  A module which communicates with GCT during instrumentation.  For
  207.      appropriate function calls or method calls, the module tells GCT how
  208.      many log entries to allocate and what the reporting tools should
  209.      report for each.
  210.  
  211. (2)  Testing versions of reusable software that mark when producer test
  212.      conditions are satisfied.
  213.  
  214. The GCT support required is being designed now.  I invite reuse providers
  215. to participate in the design.
  216.  
  217.  
  218. REFERENCES
  219.  
  220. [Glass81]
  221.      Robert L. Glass, "Persistent Software Errors", Transactions on
  222.      Software Engineering, vol. SE-7, No. 2, pp.  162-168, March, 1981.
  223.  
  224. [Johnson83]
  225.      W.L Johnson, E. Soloway, B. Cutler, and S.W. Draper.  Bug Catalogue:
  226.      I.  Yale University Technical Report, October, 1983.
  227.  
  228. [Marick92]
  229.      B. Marick, Test Condition Catalog.  Testing Foundations, Champaign, IL
  230.      61820, 1992.
  231.  
  232. [Rich90]
  233.      C. Rich and R. Waters.  The Programmer's Apprentice.  New York:  ACM
  234.      Press, 1990.
  235.  
  236.