Showing posts with label The Art of Software Testing. Show all posts
Showing posts with label The Art of Software Testing. Show all posts

Saturday, July 16, 2011

The Art of Software Testing by Glenford Myers : My Opinion

I would give this book 5 out of 5. It is a must read book for both programmers and quality assurance engineers. It should be included in colleges as a textbook along with Code Complete that I described earlier.
To make it easy to browse, I am putting links to all the chapters below:

The Art of Software Testing by Glenford Myers : Chapter 8

The author discusses about testing tools and other techniques in this chapter. The test case design has not been automated but significant advancements have been made in automating other aspects of the testing process. Some of the tools are:
  • Module driver tools: It provides a language to express test cases to test a module. The author mentions three advantages of such tool:
    1. The language reduces the effort required and standardizes the form of test cases.
    2. Rerun of test cases is easy when a correction is made to the module
    3. The automatic verification of results forces the programmer to state explicitly the expected output.
  • Static flow analysis tools: They analyze control flow and data flow of the program, they can detect following errors:
    • Variable with an undefined value
    • Variables with assigned values that are never used
    • Unreachable code
    • Inconsistent interfaces among modules
      • ACES, FACES, AUDIT, RXVP and DAVE are examples of this kind of tools.
  • Test coverage monitors: Coverage monitors are tools that monitor the subject program during execution to provide statistics to determine whether the statement-coverage and decision-coverage criteria have been met.
  • Mathematical proof of program correctness: The proof of program correctness tries to demonstrate that the program is error free. The author provides references to method of inductive assertions, predicate transformers, subgoal induction, computation induction, structural induction and intermittent assertions.
  • Program correctness provers: The goal is to create a program that, takes as input another program and its input and output assertions, attempt to prove the subject program correct.
  • Symbolic Execution: It is a hybrid between program testing and correctness provers. The subject program is executed symbolically. 
  • Test Data Generators: The author talks about several tools that generate test data to meet a specific criterion by analyzing a program's logic flow.
  • Environmental Simulators: These are useful when testing in actual environment cannot be done, test conditions are hard to create in real environment etc...
  • Sneak Circuit Analysis: 
  • Virtual Machines: They provide multiple programs impression that each is executing in separate standalone machine.
  • Testing Mathematical Software: 
  • Interactive Debugging Tools: The author discuss about EXDAMS, ISMS and CAPS.
  • Compiler Debugging Aids: Compilers can contain debugging features added to the language such as
    • Ability to designate any arbitrary statements as debugging statements and to activate and deactivate at compilation or run time.
  • Program State Monitors: It monitors a program during execution, watching for the arrival of a certain predefined conditions and/or collecting data that would be useful during debugging such as first, last, minimum and maximum of each assignment statement, minimum and maximum values of each do-loop control variable etc...
The author then discusses about software error studies, software error data-collection and predictive models.  The author then provides some statistics on testing experiments and the results. The author then provides some findings on debugging experiments.

The author discusses how computer architecture or hardware design can help debugging by providing features not present in the current computer design.

Thursday, July 14, 2011

The Art of Software Testing by Glenford Myers : Chapter 7

Debugging is defined as determining the exact nature and location of the suspected error within the program and fixing or repairing the error.

The author then discusses debugging methods:
  1. Brute-force debugging: It is the most inefficient and unsuccessful method and advises to use this only when all other method fails. The author discusses three methods of brute-force debugging.
    • Debugging with a storage dump: This is the most efficient method and the author provides a list of problems associated with this method including static nature of the dump, massive amounts of irrelevant data, etc...
    • Debugging with scattered print statements: The author also enlists the shortcomings of this technique such as massive amount of data, require to change program, etc...
    • Debugging with automated debugging tools: The author compares debugging with solving a homicide and emphasizes the use of brain over a set of aids.
  2. Debugging by Induction: The author provides steps in the induction process as follows:
    • Locate the pertinent data
    • Organize the data
    • Find relationship among data
    • Devise a hypothesis
    • Prove the hypothesis
  3. Debugging by Deduction: The author provides steps in the deduction process as follows:
    • Enumerate the possible causes
    • Use the data to eliminate the possible causes
    • Refine the remaining hypothesis
    • Prove the remaining hypothesis
  4. Debugging by Backtracking: In this method, mental reverse execution of the program is performed in which values of variables and state of the program is deduced by looking at the wrong output and the process is continued till the origin of the first unexpected state.
  5. Debugging by Testing: Separate set of "slim" test cases are developed to provide information useful in locating a suspected error.
The author then provides two set of principles:
  1. Error locating principles
  2. Error repairing principles
    • When there is one bug, there is likely to be another.
    • Fix the error, not just the symptom of it.
    • The probability of fix being correct is not 100%.
    • The probability of the fix being correct drops as the size of the program grows.
    • Beware of the possibility that an error correction creates a new error.
    • The process of error repair should put one back temporarily in design phase.
    • Change the source code, not the object code.
The author then discusses about improvement that can be achieved by careful analysis of software errors:
  1. When was the error made?
  2. Who made the error?
  3. What was done incorrectly?
  4. How could the error have be prevented?
  5. Why wasn't the error detected earlier?
  6. How could the error have been detected earlier?
  7. How was the error found?

Monday, July 11, 2011

The Art of Software Testing by Glenford Myers : Chapter 6

In this chapter, the author focuses on the part of testing that starts when human-testing ends. The author talks about origination of errors in software programming. Since software development is a process of communicating information about the program and translating it from one form to another, the vast majority of software errors are attributable to breakdowns, noise and mistakes in communication. The author then describes the flow of the software development process. The author suggests to include more precision into the development process and having a separate verification step at the end of each process. The author also suggests having distinct testing processes toward distinct development processes i.e. focus each testing process on a particular translation step. The author then discusses testing at different stage of development cycle:
  1. Function Testing: It is a process of finding discrepancies between the program and its external specification.
  2. System Testing:
    • System testing is the process of attempting to demonstrate how the program does not meet its objectives.
    • System testing is impossible if the project has not produced a written set of measurable objectives for its product.
      • The author then mentions following categories of test cases:
    • Facility Testing: It is the determination of whether each facility mentioned in the objectives was actually implemented.
    • Volume Testing: The program is subjected to heavy volume of data.
    • Stress Testing: It involves testing a program under heavy load in a short span of time.
    • Usability Testing: The author provides following aspects of usability testing
      • Does system contain excessive number of options ?
      • Does system return acknowledgment to all inputs?
      • Is the program easy to use?
      • Where accuracy is vital, is sufficient redundancy present?
      • Are the outputs of the program meaningful?
    • Security Testing: It is a process of attempting to devise test cases to subvert the program's security checks.
    • Performance Testing: Test cases should be designed to show that the program does not meet its performance objectives like response times and throughput rates.
    • Storage Testing: Test cases should be designed to show that the program does not meet storage objectives in terms of main and secondary storage and spill/temporary files.
    • Configuration Testing: The program should be tested with each kind of hardware device and with the minimum and maximum configuration. Each possible configuration of the program should also be tested.
    • Compatibility/Conversion Testing: Test cases should be designed to make sure the program meets the objectives of compatibility with and conversion procedures from, the existing system.
    • Installability Testing: Testing of installation procedures should be part of this testing.
    • Reliability Testing: If the objective of the program contain specific statements about reliability, tests should be devised to
    • Recovery Testing: Tests should be designed to see the system's recovery from programming errors, hardware failures and data errors.
    • Serviceability Testing: Serviceability objectives defined in terms of service aids, mean time to debug a problem, maintenance procedures, and quality of internal-logic documentation.
    • Documentation Testing: User documentation should be subject to an inspection for accuracy and clarity. Examples in the documentation should be part of test cases used to test the program.
    • Procedure Testing: Any human procedures involved in large programs should be tested.
      • The author clearly specifies not performing system test by programmers who have written the program as well as not within the organization developing the program.
  3. Acceptance Testing: This is carried out by conducting tests to show that the program does not do what it is contracted to do.
  4. Installation Testing: This may include test cases to check that all the files have been created and have necessary contents, all parts of the system exists and is working.
The author then discusses about test planning and enlists following components of a good test plan:
  1. Objectives: Each testing phase should have an objective.
  2. Completion criteria: Criteria for specifying the completion of each test phase needs to be specified.
  3. Schedules: The schedules for when the test cases will be designed, written and executed should be created.
  4. Responsibilities: The responsibilities of people regarding testing and fixing of errors should be clearly defined.
  5. Test-case libraries and standards: Systematic methods of identifying, writing and storing test cases are necessary.
  6. Tools: The required test tools must be identified including the owner for their development or acquisition and how to use them or when they are needed.
  7. Computer time: Each testing phase's required computer time should be calculated.
  8. Hardware configuration:
  9. Integration: System integration plan should be in place that defines the order of integration and the functional capability of each version of the system.
  10. Tracking procedures: There should be tracking of errors and the estimation of progress with respect to schedule, resources and completion criteria.
  11. Debugging procedures: Mechanisms must be in place to track the progress of corrections and adding them to the system.
  12. Regression testing: Regression testing is important because changes and error corrections tend to be more error-prone than the original code. The purpose of the regression testing is to determine if the change has regressed other aspects of the program.
The author then discusses about test completion criteria which can be two of the following:
  1. Scheduled time for testing expires.
  2. When all the test cases execute without detecting any errors.
The author describes how both the criteria are useless. The author provides three criteria
  1. The first one is based on use of testing methodologies:
    • Completion of module testing can be achieved if the test cases are derived from multi-condition coverage criterion or boundary value analysis of interface specification and all the test cases are unsuccessful.
    • Completion of function testing can be achieved if the test cases are derived from cause-effect graphing, boundary value analysis and error guessing and all the test cases are unsuccessful.
  2. The second criteria is to state the completion requirements in positive terms, i.e. test of a module is not complete till x errors are found or an elapsed time of y months. The author discuss the problem of estimating the number of errors in a program and provides several ways like
    • Experience with previous programs
    • Apply predictive models
    • Use industry-wide averages
  3. The third criteria is to plot the number of errors found per unit time during test phase. By examining the shape of the curve, it can be determined whether to finish or continue the testing.
The author again emphasizes on hiring an independent test agency to test the program.

The Art of Software Testing by Glenford Myers : Chapter 5

The author discusses about unit testing in this chapter and enlists following advantages of module testing:

  • It makes combinatorics of managing testing easier.
  • It makes debugging easier.
  • It speeds up testing since multiple modules can be tested simultaneously.
The author then takes an example and generates test cases for it.

The author then discusses incremental testing where one module at a time is integrated with already tested modules and then tested. In non-incremental testing, all the modules are first tested and then integrated to create a program. The author then provides following observations for incremental testing:
  1. Non-incremental testing requires more work.
  2. Programming errors related to mismatching interfaces or incorrect assumptions among modules will be detected earlier if incremental testing is used.
  3. Debugging becomes easier.
  4. Incremental testing results in thorough testing.
  5. Non-incremental approach uses less machine-time.
  6. Non-incremental testing can be more parallelized in the earlier phase.
The author then discuss two approaches of incremental testing:
  • Top-down approach: The author points out following shortcomings of this approach:
    • When a new module is introduced, it is impossible to test some predefined situations.
    • If the newly introduced module is at a distance from the module doing I/O operations, it is difficult to decide the set of inputs that allows to execute all tests on the newly introduced module.
    • Since displayed output is from a module large distance away from the module being tested, correlation between output and behaviour of the module is difficult to establish.
    • Even though it seems possible, it cannot be combined with top-down design.
    • Sometimes, a module may remain untested before moving to the other module.
  • Bottom-up approach: The author points out following advantages/disadvantages of this approach:
    • The working program does not get created till the last module is added.
The author then provides a list of guidelines to perform the actual test:
  • The set of test cases needs to be reviewed or inspected before the test is performed.
  • Use automated test tools.
  • Look at the side effects of a module.
  • Testing of a module should be done by programmer of a calling module.
  • Debugging should always be done by the programmer.
  • If a high number of errors are found in a subset of the modules, such modules should be subjected to further module testing.

The Art of Software Testing by Glenford Myers : Chapter 4

The author discuss about how to design test cases in this chapter. The problem is to determine what subset of the possible test cases has the highest probability of detecting the most errors. The author then tries to develop a strategy which uses black-box-oriented test-case-design methodologies combined with testing the logic of the program using white-box testing.

The author then discusses following methods of test-case design:
  1. Logic-Coverage testing: The author discusses about designing a testing strategy such that every code path is executed exactly once. The author provides an example program and shows that it is a very weak criterion. The stronger criterion for logic coverage is called decision coverage or branch coverage. The criterion states that every decision has true or false outcome at least once. Decision coverage generally satisfies the statement coverage except when
    • The program has multiple entry points
    • The program has no decisions
    • The author then discusses a stronger method called condition coverage where each condition in a decision takes on all possible outcomes at least once.
  2. Equivalence partitioning: Since exhaustive-input test of a program is impossible, selecting the subset of test cases with the highest probability of finding the most errors is required. Test case design by equivalence classes proceed in two steps:
    • Identifying the equivalence classes: Each input condition is partitioned into two or more groups such as valid equivalence class, invalid equivalence class and external condition. The author then provides some guidelines for finding equivalence classes:
      • If an input condition specifies a range of values, identify one valid equivalence class and two invalid equivalence classes.
      • If an input condition specifies the number of values, identify one valid equivalence class and two invalid equivalence classes.
      • If an input condition specifies a set of input values, identify one valid equivalence class for each value and one invalid equivalence class.
      • If a condition specifies a "must be" situation, identify one valid equivalence class and one invalid equivalence class.
    • Defining the test cases: This follows following process:
      • Assign a unique number to each equivalence class.
      • Until all valid equivalence classes have been covered by test cases, write a new test case covering as many of the covered valid equivalence classes as possible.
      • Until all invalid equivalence classes have been covered by test cases, write a test case that covers one and only one of the uncovered invalid equivalence classes.
  3. Boundary value analysis: Boundary conditions are those situations directly on, above or beneath the edges of input equivalence classes and output equivalence classes. The author then gives guidelines for boundary value analysis:
    • If an input condition specifies a range of values, write test cases for valid ends of the range and invalid-input test cases for situations just beyond ends.
    • If an input condition specifies a number of values, write test cases for the minimum and maximum number of values and one beneath and beyond these values.
    • Try to create input conditions that test boundaries of output range and beyond.
    • Try to create input conditions that test boundaries of output values and beyond.
  4. Cause Effect Graphing: This technique can explore combinations of input circumstances. The author then describe a process to derive test cases using this method. The author then take an example and apply the method to derive test cases.
  5. Error Guessing: it is not possible to give exact procedure for this technique since it is intuition based or ad-hoc. The author then provides an example of how to guess errors.
The author then provides a final strategy which is a combination of the methods provided earlier as follows:
  1. Use Cause Effect Graphing from specification of input conditions.
  2. Use Boundary Value Analysis
  3. Identify valid and invalid equivalence classes for the input and output.
  4. Use error-guessing techniques to add additional test cases.
  5. Use decision coverage, condition coverage, multiple-condition coverage to meet coverage criterion.