CS210 · Block 3 · Lesson 26

Test Planning and Unit Testing

Test plans · Normal, edge, and error cases · assert · Unit tests · Suite thoroughness
At a glance: For twenty-five lessons the autograder tested your code. Today the roles flip: you learn to test code yourself. You will build a test plan that covers normal, edge, and error cases, write unit tests with assert, and judge whether a passing suite is actually thorough. The hands-on practice happens through the assert walkthrough in Section 5; the lab puts you on the other side of the autograder, writing the tests that hold a module accountable.
Contents
  1. Lesson Objectives
  2. Assigned Readings
  3. Pre-Class Work
  4. Lesson Materials and Overview
  5. In-Class Work
  6. After Class
1. Lesson Objectives

By the end of this lesson, cadets will be able to:

  1. Develop a test plan that covers normal cases, edge cases, and error conditions. (Outcome 3)
  2. Implement unit tests for C functions using assert and a simple test runner. (Outcomes 3, 7)
  3. Evaluate the thoroughness of a test suite. (Outcome 3)
2. Assigned Readings

Complete before class. These set the vocabulary we will use.

Reading Source
Test planning and unit testing in depth: test plans, the normal / edge / error breakdown, assert, and judging suite thoroughness. Supplementary notes (instructor-written)

There is no Beej chapter for this lesson. The instructor-written notes are the assigned reading; they line up section for section with the overview in Section 4.

3. Pre-Class Work
  • Read the supplementary notes
    Read the instructor-written notes listed in Section 2. They introduce the test-plan vocabulary and the assert macro you will use in class.
  • Take the test-plan self-check
    The self-check quiz in Section 5 is a good warm-up. It is short, it gives you a completion code, and it surfaces the normal / edge / error distinction before you have to apply it in the lab.
  • Skim the In-Class section below
    Know what you are walking into. Today's lab flips the autograder around: you write the tests.
Your team's design check-in is due this lesson. If your team is behind on it, schedule EI before class so it does not eat your lab time.
4. Lesson Materials and Overview

You have been on the receiving end of tests since Lesson 1: write code, push it, see whether the autograder turns green. Today you learn to build that green yourself. Testing is not a chore you do at the end; it is how you decide whether code can be trusted at all. The material below is the spine of the lecture and the reference you will use during the lab.

Jump to
Slides Why Test The assert Macro Building a Test Plan Unit Tests in C Suite Thoroughness

Slides

The Lesson 26 deck covers why we test, the assert macro, the normal / edge / error breakdown of a test plan, writing unit tests with a simple runner, and how to judge whether a suite is thorough. The slides are the spine of the in-class lecture; the assert walkthrough is where you practice each idea hands-on.

Open Lesson 26 slides →

Why test at all

Code that compiles is not code that works. A function can build cleanly, run without crashing, and still return the wrong answer on inputs you did not try. Testing is the discipline of trying those inputs on purpose, before your users (or your teammates, or a graded review) try them for you.

There is one rule that shapes everything else in this lesson: tests can show the presence of bugs, but never their absence. A passing test tells you the code is correct for that one case. It says nothing about the cases you did not write. That is why a test plan matters more than raw test count: thoroughness comes from choosing the right cases, not from piling up more of the same.

The assert macro

C's simplest test tool lives in <assert.h>. You give assert a condition. If the condition is true, nothing happens and the program continues. If it is false, the program prints the failing expression with its file and line, then aborts immediately.

#include <assert.h>

int total = add_scores(7, 5);
assert(total == 12);  // silent if correct; aborts if not

That hard, loud stop is the point. A bug cannot hide when assert halts the program on it. The core unit-test pattern is one line:

assert(actual == expected);

The left side is what your code produced; the right side is the answer you worked out by hand before running it. One caution that bites every C programmer eventually: use == for comparison, never a single =. A single = is assignment, which would overwrite your value and quietly pass. Practice this in the assert walkthrough in Section 5.

Building a test plan: normal, edge, error

A test plan is a short list, written before you write the tests, of the cases that matter. The reliable way to build one is to walk three categories for every function:

Category What it means
Normal Ordinary, in-range input the function plainly should handle. A populated list, a typical value.
Edge The boundaries. Empty input, a single element, a value sitting exactly on a threshold, the largest allowed value, all-equal or all-negative data.
Error Input the contract calls out specially: a value not found, a count of zero that must not divide, anything the function is supposed to reject or handle defensively.

Most bugs live at the edges and error conditions, not in the normal cases. A function that passes every normal case can still divide by zero on an empty list or return an off-by-one rank for the top element. Writing the plan first forces you to name those cases before the code lulls you into thinking it works.

Unit tests in C

A unit test checks one function in isolation. In this course a test is a small void function full of assert calls. You build an input, call the function, and assert on the result:

void test_highest_empty(void)
{
  player_t board[1] = {0};
  // empty board: contract says return -1
  assert(highest_score(board, 0) == -1);
}

Because a failed assert aborts the whole program, running many tests in one run needs a little infrastructure: a test runner that runs each test in isolation so one failure does not hide the rest. The lab provides that runner; you write the tests and register them. You have seen this multi-file shape since Lesson 20: a header declares the contract, an implementation honors it, and now a third file tests it.

Judging suite thoroughness

Once you have a suite, the last skill is judging whether it is any good. The trap is to count assertions: a suite with fifteen assertions all on typical mid-range inputs is weaker than a suite of six that reaches the empty case, the boundary case, and the error case. Coverage of categories beats raw count.

A practical way to judge a suite: for each function, can you point to at least one normal case, one edge case, and one error case? If a whole category is missing, that is exactly where a bug will slip through. The lab makes this concrete by grading your suite against a buggy module: you earn credit for the bugs your tests actually catch, and the only way to catch them all is to test the boundaries. All of this becomes hands-on in the assert walkthrough in Section 5; the self-check quiz there lets you rehearse the normal / edge / error judgment before the lab.

5. In-Class Work

Three things to do in class. Use the checklist to track your progress.

  • Work through the assert walkthrough below. Thirteen guided tasks covering assert basics, the actual-equals-expected pattern, and writing tests that catch real bugs. About 20 minutes.
  • Take the test-plan self-check. Six questions on classifying normal / edge / error cases and judging thoroughness. About 10 minutes.
  • Complete Lab 26: Testing the Leaderboard Module. Auto-graded through GitHub Classroom. You write the test suite; the autograder grades it against correct and buggy modules. Full instructions in the lab repo.

assert Walkthrough

Thirteen tasks across three sections. Type one line at a time at the prompt. The terminal shows what your program did when it ran; the right pane is your running test report.

Before you begin

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 26 reflection.

CS210 Lesson 26 · assert Walkthrough

A guided tour through assert: the simplest test oracle in C. Type each line at the prompt. The terminal shows what your program did when it ran; the right pane is your running test report. A failing assertion stops the program cold, just like the real assert.h.
Task 0 of 13
Section 1: assert basics
Current task
Loading...
Test report
No assertions run yet.
Type an assert on the left.
assertlab>
How this works: This is not a Linux terminal. It is a teaching tool that runs a small slice of C: integer expressions, comparisons, a few named values, and the assert macro. The task card tells you what to type next; only the expected line advances the walkthrough so the test report stays predictable. Mistype twice and the hint button will pulse. When you finish, free mode unlocks so you can write your own assertions.

Test Plan Self-Check

Six questions. Pick or type your answer, submit, and read the feedback before moving on. Pass at 70% or above; below that, review and take it again.

Before you begin

Enter your name. It will appear on the score card so you can include it in your screenshot for the Lesson 26 reflection.

CS210 Lesson 26 · Test Plan Self-Check

Six questions on building a test plan: classifying cases as normal, edge, or error; spotting the case a suite is missing; and judging whether a green suite is actually thorough. Pass at 70% or above; below that, take it again after reviewing.
How this works: One question per card. Pick or type your answer and click Submit. Feedback appears, then click Next to move on. Answers lock once submitted, so think before you submit. After all six, you get a score, a completion code, and a per-question recap.
6. After Class
  • Finish Lab 26 if you did not complete it in class. Submit tests.c through GitHub Classroom before Lesson 27.
  • Complete the Lesson 26 reflection in Blackboard. Enter both widget completion codes and answer the reflection prompt; attach your screenshots of the completion screens.
  • Read the ACM Code of Ethics and Professional Conduct (acm.org) for the Lesson 27 ethics lesson.
  • Take the testing mindset into your team PEX. Your team's test plan check-in is due at Lesson 29; start listing normal, edge, and error cases for your project's functions now.
  • Heads up: GR3 at Lesson 28 covers Lessons 18 through 27, including today's testing material.
Need help? Schedule EI with your instructor. Bring your tests.c, the autograder output you do not understand, and the case you are stuck testing. Specific questions get unstuck quickly. A course Resources section collects the standing references (the DFCS C Programming Standard, the Git troubleshooting card, and more) for self-service.