CSC 101 Lecture Notes Week 3, Part 2
Problem, Problem, Problem, Solving


Relevant Reading: Sections 2.8, 3.6, 4.9




  1. There are several different problems we're trying to solve when we write a program.

    1. The user's problem -- given an English description of some problem, write a program to solve it.

    2. The testing problem -- given a program that purports to solve the user's problem, make sure it really does.

    3. The debugging problem -- given a program that doesn't work right, fix it.


  2. Solving the users's problem.

    1. You need to learn to think algorithmically, by coming up with step-by- step solutions to particular problems.

    2. For bigger problems, you need to learn how to decompose the problem into smaller sub-problems.

    3. You also need to learn and master at least one programming language.

    4. Then you need to learn how to apply it to a variety of different problems.

    5. You do all this by writing a lot of programs, starting with simple ones, and eventually getting to more complicated problems.


  3. Solving the testing problem.

    1. First you need to get your program to compile.

    2. Then you need to come up with a set of test cases.

    3. Each test case has:

      1. program inputs

      2. expected program outputs

    4. Then you need to run the program and see if your program's actual output matches the expected output for each test case.

    5. When it doesn't match, you've got one or more program bugs, which you need to exterminate; i.e., you need to debug your program.


  4. Solving the debugging problem

    1. Determine which part(s) of the program is(are) causing the problem.

    2. Analyze the nature of the failure to determine what to fix, in particular determine if

      1. you're not executing parts of a program you were expecting to;

      2. you're not executing parts of a program in the order you were expecting to;

      3. there's some flaw in your program logic, i.e., the way the algorithm was translated into C code.


  5. Specific techniques for generating test cases.

    1. Choose some typical test cases, such as the ones used for examples in the spec.

    2. Create test for a range of legal input values.

      1. Have test cases at the lower boundary for each input.

      2. Have test cases at the upper boundary for each input.

      3. Have test cases one unit above lower boundaries.

      4. Have test cases one unit below upper boundaries.

      5. Have tests for different combinations of inputs:

        1. with one input value varying, all other input values fixed

        2. with varying combinations of inputs that focus on a particular aspect of the problem

    3. Create test cases the produce a range of different possible outputs.

      1. Have test cases that produce the lower boundary value for each output.

      2. Have test cases that produce the upper boundary value for each output.

      3. Have test cases that produce output one unit above the lower boundaries.

      4. Have test cases that produce output one unit below the upper boundaries.

      5. Have tests for different combinations of expected output:

        1. with one output value varying, all other output values fixed

        2. with varying combinations of inputs that produce outputs for a particular aspect of the problem

    4. Create tests that exercise certain aspects of your program logic

      1. each conditional expression is evaluated with all possible boolean values

      2. all loops are fully exercised (discussion of program loops is coming up next week)

    5. Have enough tests to make sure that every statement in your program gets executed at least one time, i.e., that your tests fully cover the program.

    6. When the program does error handling, create test cases that produce each form of error.


  6. Specific techniques for program debugging.

    1. Program inspection.

      1. Carefully inspect the program overall, by yourself.

      2. Have another programmer inspect your program, such as one you're paired with in lab. Note that for CSC 101, you only have your lab programs inspected, since you're required to work on the programming assignments on your own.

      3. Have one or more other colleagues inspect the program.

    2. Compare your program to a similar program that works.

      1. This can be particularly useful during incremental development.

      2. Save each working version as you develop.

      3. Then when you add new features that break something, compare your current version with the previous working version.

    3. Based on particular failing test cases, isolate the program location that's causing the bug.

      1. See if the test case itself provides help with this, e.g., if a particular failure points to some specific function in the program.

      2. Put intermediate print statements in your program, to print out variable and expression values.

      3. Use a program debugger to stop at intermediate points in your program, and then look at variable and expression values.

    4. Write a program test driver, that calls individual functions, each with their own test cases.

      1. This becomes effective when a program has many functions, that each do non- trivial computations.

      2. We'll investigate this form of testing starting next week.




index | lectures | handouts | programs | labs | examples | solutions | grades