# Testing Small Programs

Computer Science I · Programming I · https://tryals.app/learn/computer-science-i/testing-small-programs

Writing code is only half the job; the other half is gaining confidence that it is **correct**. **Testing** does this by running the program on chosen inputs and comparing its actual output against the **expected output** you worked out independently.

A single **test case** is a pair: an input, and the output it should produce. A useful test suite covers three kinds of input:

| Input Type | Description & Examples |
| --- | --- |
| **Typical cases** | Ordinary, representative inputs (does `double(4)` give `8`?) |
| **Edge cases** | Boundaries where bugs hide: zero, empty lists, extremes, negative numbers |
| **Invalid cases** | Inputs the program should reject or handle gracefully |

The mindset is adversarial: a good tester actively tries to **break** the program, not just confirm it works. Passing a hundred typical cases proves little if an overlooked edge case still crashes it.

## Limits and Automation

Testing famously **cannot prove a program correct** because you cannot try every possible input. However, a well-chosen suite can reveal the **presence** of bugs cheaply and repeatably.

Automated tests are especially valuable because they can be re-run after every change. A **regression test** confirms that nothing which used to work has broken during updates.

> **Common pitfall:** Testing only happy-path typical inputs and skipping edge cases. Most real bugs surface at boundaries like zeros, empty lists, or off-by-one indices. A test suite without edge cases gives false confidence; deliberately probe the boundaries.

## Practice questions

6 of this lesson's 11 practice questions, with answers. The full set is in the app.

### 1. A program that passes one hundred typical-case tests is guaranteed to have no bugs.

**Answer:** False

**Why:** False. A hundred typical cases prove nothing about the edge cases — an empty input, a zero, an off-by-one boundary — where most real bugs live. Testing reveals the presence of bugs cheaply, but no finite suite can guarantee their absence.

Page: https://tryals.app/practice/computer-science-i/testing-small-programs/a-program-that-passes-one-hundred-typical-case-tests-is-guaranteed-to

### 2. A function is meant to accept a whole number of items. Sort each test input by its kind.

**Answer:**

- Typical case: The number 7
- Edge case: The number 0, An empty list
- Invalid case: The text "hello" where a number is expected

**Why:** Ordinary values like 7 and 12 are typical; zero, an empty list and the maximum are edges where bugs love to hide; non-numeric text is invalid and should be handled gracefully. Testing only typical cases is exactly the false confidence the lesson warns against.

Page: https://tryals.app/practice/computer-science-i/testing-small-programs/a-function-is-meant-to-accept-a-whole-number-of-items-sort-each-test

### 3. Order the steps of writing and running one test case.

**Answer:**

1. Choose an input to test
2. Work out the expected output independently, by hand
3. Run the program on that input
4. Compare the actual output with the expected output

**Why:** Pick an input, decide the expected output independently, run, then compare. Working out the expected result independently is essential, if you take the answer from the program itself, the test can never catch a wrong answer.

Page: https://tryals.app/practice/computer-science-i/testing-small-programs/order-the-steps-of-writing-and-running-one-test-case

### 4. A test suite that passes on typical inputs can miss bugs that a handful of edge cases would catch immediately. Why are the edges so much more productive to test than the middle?

A. Because testing edge cases is faster, so more tests can be run in the same time.
B. Because bugs cluster where behaviour changes, while typical inputs share one path.
C. Because edge cases are the only inputs a user will ever supply in practice.
D. Because typical inputs are handled by the language rather than by the program.

**Answer:** B. Because bugs cluster where behaviour changes, while typical inputs share one path.

**Why:** Ten typical inputs usually walk the same route, so the tenth tells you almost nothing the first did not, where each edge probes somewhere different: empty tests the zero-iteration path, one element tests initialisation, the maximum tests overflow. Property-based tools generate inputs systematically and find edges humans do not think of, which says something about how far intuition gets you.

Page: https://tryals.app/practice/computer-science-i/testing-small-programs/a-test-suite-that-passes-on-typical-inputs-can-miss-bugs-that-a

### 5. A test asserts that a function returns something, and passes even when the function returns the wrong answer. What has been tested?

A. The return type, which is sufficient for most purposes
B. That the code ran without raising, which is liveness rather than correctness
C. The function's performance, which is what non-specific assertions measure
D. Nothing, since a passing test always indicates correct behaviour

**Answer:** B. That the code ran without raising, which is liveness rather than correctness

**Why:** It proves the function did not crash, and nothing about the answer. That is the gap coverage metrics cannot see: every line ran, so the report is green, and the assertion never compared anything. A test is only as strong as what it asserts, which is why 'assert not None' is barely a test at all.

Page: https://tryals.app/practice/computer-science-i/testing-small-programs/a-test-asserts-that-a-function-returns-something-and-passes-even

### 6. A function takes a list of numbers. Select every input that is an edge case worth testing.

A. An ordinary list of five mid-range numbers
B. A list of three unremarkable numbers
C. An empty list
D. A list with exactly one element
E. A list containing the largest allowed value

**Answer:** C. An empty list; D. A list with exactly one element; E. A list containing the largest allowed value

**Why:** An empty list, a single-element list and the largest value are all boundaries where bugs cluster. The two ordinary five- and three-number lists are typical cases, useful, but not the boundaries where most real bugs surface.

Page: https://tryals.app/practice/computer-science-i/testing-small-programs/a-function-takes-a-list-of-numbers-select-every-input-that-is-an
