# Testing Larger Behaviours

Computer Science I · Programming II · https://tryals.app/learn/computer-science-i/testing-larger-behaviours

## Testing at Scale

Testing a single function is one thing; gaining confidence in a whole program is another. As programs grow, testing organizes into **levels**.

A **unit test** checks one small piece, a single function or module, in isolation, with dependencies controlled. It is fast and pinpoints failures. An **integration test** checks that several units work correctly together, verifying that module interfaces fit. A module can pass unit tests yet fail integration because of shared interface disagreements. **System (end-to-end) tests** exercise the whole program as a user would.

| Level | Scope | What it verifies |
| --- | --- | --- |
| **Unit** | One function/module | Isolated logic |
| **Integration** | Multiple modules | Shared interfaces |
| **System** | Entire program | User-facing behavior |

## Coverage & Safety

**Test coverage** measures how much code the tests exercise, such as the fraction of lines or branches that run during testing. It acts as a necessary base, but it is not sufficient for correctness.

Two enabling practices keep codebases healthy:
- **Automated tests**: re-run cheaply after every code change.
- **Regression safety net**: catches when a change breaks previously working behavior.

> **Common pitfall:** treating **high code coverage** as proof of correctness. Coverage only measures which code ran, not whether results were checked or edge cases exercised. A suite can hit 100% coverage while asserting nothing meaningful.

## Practice questions

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

### 1. Sort each claim by whether a coverage report can actually support it.

**Answer:**

- Coverage can tell you this: Which lines never ran during the test suite, What fraction of branches were taken at least once, That there is code in the program nobody has verified
- Coverage cannot tell you this: That the results produced by the tested lines were checked, That every edge case of the tested code was exercised, That the program is correct

**Why:** A coverage tool observes execution, so it can report untouched lines and branch percentages, and untouched code is genuinely unverified. It cannot see whether any result was compared against an expectation, so it cannot speak to edge cases or correctness. This is why coverage is a floor, not a guarantee.

Page: https://tryals.app/practice/computer-science-i/testing-larger-behaviours/sort-each-claim-by-whether-a-coverage-report-can-actually-support-it

### 2. Every unit test in a project passes. Select every kind of defect that could still be present.

A. A module has a syntax error that stops it compiling
B. A function fails on the exact input its unit test supplies
C. A function returns the wrong value for an input no test supplies
D. Two modules disagree about the format of the data they exchange
E. The program is unusable end to end even though each part works

**Answer:** C. A function returns the wrong value for an input no test supplies; D. Two modules disagree about the format of the data they exchange; E. The program is unusable end to end even though each part works

**Why:** Isolation is the blind spot: interface disagreements and end-to-end failures survive a green unit suite, as do inputs nobody thought to test. A function failing on its own test input, or code that will not compile, could not coexist with a passing suite, which is why integration and system tests sit above the unit level rather than replacing it.

Page: https://tryals.app/practice/computer-science-i/testing-larger-behaviours/every-unit-test-in-a-project-passes-select-every-kind-of-defect-that

### 3. Test-driven development requires the new test to FAIL before any code is written. Why is that step not a waste of time?

A. Because a test that passes before the feature exists is testing nothing
B. Because the compiler needs the failure to generate the stub
C. Because failing tests are required by most continuous-integration systems
D. Because it establishes a baseline measurement of performance

**Answer:** A. Because a test that passes before the feature exists is testing nothing

**Why:** The red step validates the test itself. Skipping it is how suites fill with tests that would pass no matter what the code did.

Page: https://tryals.app/practice/computer-science-i/testing-larger-behaviours/test-driven-development-requires-the-new-test-to-fail-before-any-code

### 4. A test suite runs in four hours and developers stop running it before pushing. What has the suite become?

A. More thorough, since longer suites test more behaviour
B. Correct, since test duration does not affect what it catches
C. Nearly worthless, since a test that is not run catches nothing
D. A performance problem for the build server rather than for developers

**Answer:** C. Nearly worthless, since a test that is not run catches nothing

**Why:** Feedback that arrives after you have moved on is barely feedback, and a suite people skip catches nothing at all. That is why fast unit tests are separated from slow integration ones, and why suite runtime is treated as a first-class engineering concern rather than an inconvenience.

Page: https://tryals.app/practice/computer-science-i/testing-larger-behaviours/a-test-suite-runs-in-four-hours-and-developers-stop-running-it-before

### 5. A test suite can execute every line of a function and still miss the input that breaks it.

**Answer:** True

**Why:** True. Coverage records that a line *ran*, not that its result was asserted or that it ran with the value that fails. `return a / b` reports full coverage while never seeing b = 0. Coverage is a useful floor, uncovered code is certainly untested, and a worthless ceiling.

Page: https://tryals.app/practice/computer-science-i/testing-larger-behaviours/a-test-suite-can-execute-every-line-of-a-function-and-still-miss-the
