CSC 101 Lecture Notes Week 3, Part 2
Problem, Problem, Problem, Solving
Relevant Reading: Sections 2.8, 3.6, 4.9
-
There are several different problems we're trying to solve when we
write a program.
-
The user's problem -- given an English description of some problem,
write a program to solve it.
-
The testing problem -- given a program that purports to solve the
user's problem, make sure it really does.
-
The debugging problem -- given a program that doesn't work right, fix
it.
-
Solving the users's problem.
-
You need to learn to think algorithmically, by coming up with step-by-
step solutions to particular problems.
-
For bigger problems, you need to learn how to decompose the problem into
smaller sub-problems.
-
You also need to learn and master at least one programming language.
-
Then you need to learn how to apply it to a variety of different problems.
-
You do all this by writing a lot of programs, starting with simple
ones, and eventually getting to more complicated problems.
-
Solving the testing problem.
-
First you need to get your program to compile.
-
Then you need to come up with a set of test cases.
-
Each test case has:
-
program inputs
-
expected program outputs
-
Then you need to run the program and see if your program's actual output
matches the expected output for each test case.
-
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.
-
Solving the debugging problem
-
Determine which part(s) of the program is(are) causing the problem.
-
Analyze the nature of the failure to determine what to fix, in particular
determine if
-
you're not executing parts of a program you were expecting to;
-
you're not executing parts of a program in the order you were expecting to;
-
there's some flaw in your program logic, i.e., the way the algorithm was
translated into C code.
-
Specific techniques for generating test cases.
-
Choose some typical test cases, such as the ones used for examples in the spec.
-
Create test for a range of legal input values.
-
Have test cases at the lower boundary for each input.
-
Have test cases at the upper boundary for each input.
-
Have test cases one unit above lower boundaries.
-
Have test cases one unit below upper boundaries.
-
Have tests for different combinations of inputs:
-
with one input value varying, all other input values fixed
-
with varying combinations of inputs that focus on a particular aspect of the
problem
-
Create test cases the produce a range of different possible outputs.
-
Have test cases that produce the lower boundary value for each output.
-
Have test cases that produce the upper boundary value for each output.
-
Have test cases that produce output one unit above the lower boundaries.
-
Have test cases that produce output one unit below the upper boundaries.
-
Have tests for different combinations of expected output:
-
with one output value varying, all other output values fixed
-
with varying combinations of inputs that produce outputs for a particular
aspect of the problem
-
Create tests that exercise certain aspects of your program logic
-
each conditional expression is evaluated with all possible boolean values
-
all loops are fully exercised (discussion of program loops is coming
up next week)
-
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.
-
When the program does error handling, create test cases that produce each form
of error.
-
Specific techniques for program debugging.
-
Program inspection.
-
Carefully inspect the program overall, by yourself.
-
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.
-
Have one or more other colleagues inspect the program.
-
Compare your program to a similar program that works.
-
This can be particularly useful during incremental development.
-
Save each working version as you develop.
-
Then when you add new features that break something, compare your current
version with the previous working version.
-
Based on particular failing test cases, isolate the program location that's
causing the bug.
-
See if the test case itself provides help with this, e.g., if a particular
failure points to some specific function in the program.
-
Put intermediate print statements in your program, to print out variable and
expression values.
-
Use a program debugger to stop at intermediate points in your program, and then
look at variable and expression values.
-
Write a program test driver, that calls individual functions, each
with their own test cases.
-
This becomes effective when a program has many functions, that each do non-
trivial computations.
-
We'll investigate this form of testing starting next week.
index
|
lectures
|
handouts
|
programs
|
labs
|
examples
|
solutions
|
grades