Testing Programs Against Valid and Invalid Input
A program is correct when it accomplishes the task it was designed to perform, and this is judged against the inputs it is meant to handle.
Why a Crash Is Not the Whole Story
A common first instinct is to judge a program by how it behaves when things go wrong. If the program crashes, the reasoning goes, then it must be incorrect. If it stays calm and produces a neat result every time, it must be correct. This instinct feels reasonable, but it merges two separate questions: whether a program does its job, and whether it survives situations it was not meant to face. This article separates those two questions. The two ideas it keeps apart are called correctness and robustness. Both are ways of evaluating a program, but they measure different things.
Before reading on, commit to an answer to the following scenario. Imagine a program whose job is to read a list of numbers from the user and print them in sorted order. Suppose that for every valid list of numbers it sorts correctly, but when the user types a word such as seven instead of a number, the program stops with an error and quits. Would you call this program correct? Would you call it robust? Decide on both answers before continuing.
Tracing Valid and Invalid Input Through a Sorting Program
The sorting program from the opening scenario has a single designed task: read numbers and print them in sorted order. Follow what happens to its flow under two kinds of input. A valid input is a list of numbers the program is meant to handle. An illegal or unexpected input is something outside that expected range, such as a word where a number was expected. The diagram below traces the two paths. Notice that they diverge at the moment the program checks the input, and that the two paths lead to different kinds of outcome.
Running the sorting program on two inputs
The program reads numbers and prints them in sorted order. Trace it on the valid input 4 1 3 and then on the invalid input seven.
- 1Valid input arrives
The user enters the numbers 4 1 3. Every item is a number, so the program takes the sort path.
- 2Sorting runs
The program produces 1 3 4. This output is the designed task being carried out, so this run is evidence about correctness.
- 3Invalid input arrives
The user enters the word seven. The input is outside the range the program is meant to handle, so the program takes the error path.
- 4Reasonable response
The program prints an error message and ignores the bad input. It does not crash, and it does not guess what the user meant. This run is evidence about robustness.
The same program handled a valid input by doing its job and an invalid input by responding reasonably. Each run answers a different question.
What Correctness Asks
A program is correct when it accomplishes the task it was designed to perform, and this is judged against the inputs it is meant to handle.
The standard for correctness is the task itself. For the sorting program, correctness means producing sorted output for any set of input numbers it is meant to accept. Correctness is tested with the inputs the program is supposed to handle, and it asks a single question: does the program reach its goal? A single set of numbers that comes out unsorted is enough to show that the program fails its task.
What Robustness Asks
A program is robust when it handles illegal inputs and unexpected situations in a reasonable way, such as reporting an error and ignoring bad input rather than crashing.
Robustness is tested with inputs outside the expected range, and it asks whether the program fails gracefully. The standard here is reasonableness, not perfection. The sorting program does not need to guess what the user meant by a word, and it does not need to recover every possible value. It needs to avoid a crash or nonsensical output, and to respond in a way a sensible person would consider acceptable.
The source contrasts this with a non-robust program. Given the same bad input, such a program might crash or give nonsensical output. Both programs could be identical on every valid list of numbers. The difference appears only when the input falls outside what the program was built to expect.
Separating the Two Properties
Correctness and robustness are separate properties, so a program can be correct without being robust. The clearest way to see this is to put the two standards side by side. Each property has its own test inputs, its own question, and its own example from the sorting program. The comparison below shows how the same program is judged under each standard.
| Aspect | Correctness | Robustness |
|---|---|---|
| Defining question | Does the program accomplish its designed task? | Does the program handle illegal or unexpected input reasonably? |
| Inputs used for testing | Inputs the program is supposed to handle | Inputs outside the expected range |
| Standard of success | Reaching the goal, such as producing sorted output | Failing gracefully, such as reporting an error rather than crashing |
| Sorting program example | Every valid list comes out sorted | The word seven produces an error message and is ignored |
| Required for every program? | Yes, because a program that does not do its task has no value | Not always; the required level depends on the program's users and usage |
The two properties are judged against different conditions, so a program can pass one test and fail the other.
Because the conditions differ, the two verdicts can diverge. A program that sorts every valid list correctly but crashes on the word seven is correct and not robust. A program that politely reports an error for every bad input but sorts the valid lists incorrectly is robust and not correct. The first of these is the scenario the article opened with. Its crash tells you about robustness, and by itself says little about whether the program does its job.
Deciding How Much Robustness to Build
The source makes an important distinction. Every program should be correct, but not every program needs to be completely robust. Whether it does depends on who will use the program and how it will be used. The same program can reasonably need different levels of robustness depending on its audience.
A small utility program that you write for your own use does not have to be particularly robust. You know what inputs you will give it, you can recover quickly if it fails, and nobody else depends on it. Lower robustness is a sensible choice here.
A program released to many users who may type anything, or one whose failures would cause real harm, deserves much more care about unexpected situations. Here the cost of an ungraceful failure falls on people other than the author, so more robustness is warranted.
When deciding how much robustness to build, ask two questions drawn from the source: who will use the program, and how will they use it? A private tool used only by its author needs less invalid-input handling than a public program that strangers will feed unpredictable data. Correctness, however, is required in both cases.
Mistakes When Judging Programs
Common mistake Judging correctness by how the program handles bad input
What it looks likeConcluding that the sorting program is incorrect only because it crashes on the word seven.
Why it failsA crash on illegal input is evidence about robustness. Correctness is tested with the inputs the program is supposed to handle.
Do this insteadTest the valid inputs for correctness and the invalid inputs for robustness, and record the two verdicts separately.
Common mistake Assuming a calm program must be correct
What it looks likeSeeing the sorting program print an error message and conclude that it sorts properly.
Why it failsGraceful handling of bad input says nothing about whether valid lists are sorted.
Do this insteadCheck the designed task directly, for example by confirming that valid lists come out sorted.
Common mistake Demanding perfect robustness from every program
What it looks likeInsisting that a private one-off utility recover from every possible malformed value.
Why it failsThe source states that not every program needs to be completely robust. The required level depends on users and usage.
Do this insteadMatch the robustness effort to the audience and the consequences of failure.
Common mistake Treating robustness as guessing the user's intent
What it looks likeHaving the sorting program try to work out what seven was supposed to mean.
Why it failsThe standard for robustness is reasonableness. The program does not need to guess what the user meant.
Do this insteadReport a sensible error and ignore the bad input, which avoids both a crash and nonsensical output.
Practice Separating the Two Verdicts
A program reads a list of exam scores and prints their average. For every valid list of scores it prints the correct average. When a user types a blank line, it prints the average as a crash message and stops. State whether the program is correct, whether it is robust, and which input supports each verdict.
Hints
- Start by asking what the designed task is, then which inputs that task is meant to handle.
- Correctness is judged on valid lists of scores; robustness is judged on the blank line.
- The program can have one property without the other, so give each verdict its own justification.
For a program you might write for a classmate who will use it on unknown data, list two inputs you would test for correctness and two you would test for robustness. Then decide how much robustness this program needs, and explain your answer using the audience and usage context.
Hints
- Correctness inputs are ones the program is designed to handle.
- Robustness inputs are illegal or unexpected, and the audience changes how much attention they deserve.
Key Takeaways
- A program is correct when it accomplishes the task it was designed to perform, judged against the inputs it is meant to handle.
- A program is robust when it handles illegal or unexpected inputs reasonably, such as reporting an error and ignoring bad input rather than crashing.
- Correctness and robustness are separate properties, so a program can be correct without being robust, and the two are tested with different inputs.
- Every program should be correct, but the level of robustness it needs depends on who will use it and how.