Worked example, a passing and a failing test

This walks through real output. The routine under test is a small amount classifier.

CREATE FUNCTION classify_amount(p_amount numeric) RETURNS text AS $$
BEGIN
    IF     p_amount < 0   THEN RETURN 'negative';
    ELSIF  p_amount = 0   THEN RETURN 'zero';
    ELSIF  p_amount < 100 THEN RETURN 'small';
    ELSE                       RETURN 'large';
    END IF;
END;
$$ LANGUAGE plpgsql;

Running unitautogen --schema public generated 11 tests at 100% branch and 100% statement coverage. Each decision got a true-side and a false-side test, and the routine's actual output was recorded as the expected value. Two of the generated tests follow.

-- test_08 : the "< 100" decision, TRUE side (input 1)
RETURN NEXT is( (public.classify_amount((1)::numeric))::text,
                'small',
                'branch :: ELSIF p_amount < 100  =>  TRUE :: returns' );

-- test_09 : the "< 100" decision, FALSE side (input 100)
RETURN NEXT is( (public.classify_amount((100)::numeric))::text,
                'large',
                'branch :: ELSIF p_amount < 100  =>  FALSE :: returns' );

All tests pass on the correct code

ok 7  - test_classify_amount.test_07_branch_elsif_p_amount_0_false
ok 8  - test_classify_amount.test_08_branch_elsif_p_amount_100_true
ok 9  - test_classify_amount.test_09_branch_elsif_p_amount_100_false
ok 10 - test_classify_amount.test_10_returns_a_stable_result_set_shape
ok 11 - test_classify_amount.test_11_returns_rows_matching_baseline
1..11

test_09 calls classify_amount(100) and expects 'large'. The routine takes the ELSE branch for 100 and returns 'large', so the assertion holds. Each passing line means the routine still does, for that input, what it did when the test was written.

The same tests fail after a code change

Now a developer renames the middle tier in a one-line change.

-    ELSIF  p_amount < 100 THEN RETURN 'small';
+    ELSIF  p_amount < 100 THEN RETURN 'reduced';

Re-running the same, unchanged tests gives this.

ok 6  - test_classify_amount.test_06_branch_elsif_p_amount_0_true
not ok 7 - test_classify_amount.test_07_branch_elsif_p_amount_0_false
    # Failed test 7: "branch :: ELSIF p_amount = 0  =>  FALSE :: returns"
    #         have: reduced
    #         want: small
not ok 8 - test_classify_amount.test_08_branch_elsif_p_amount_100_true
    # Failed test 8: "branch :: ELSIF p_amount < 100  =>  TRUE :: returns"
    #         have: reduced
    #         want: small
ok 9  - test_classify_amount.test_09_branch_elsif_p_amount_100_false
not ok 11 - test_classify_amount.test_11_returns_rows_matching_baseline
    # (re-bless: accept the new output as the baseline once it is intended)
1..11
# Looks like you failed 3 tests of 11

test_08 calls classify_amount(1) and still expects 'small', the value recorded when the test was generated. The routine now returns 'reduced', so pgTAP reports have reduced, want small. The test caught that the behaviour changed for an input it used to handle a certain way.

test_09 still passes, because the change did not touch the ELSE branch. A real behaviour change fails exactly the tests whose recorded result moved and leaves the rest green, so a failure points straight at what changed.

The same runs, as an HTML report

Test results report with 11 passing tests, then 3 failing tests with have and want after a one-line change
Run 1 on the correct code, 11 of 11 pass. Run 2 after the one-line change, the two arms whose pinned value moved fail, plus the rows baseline check.

A freshly generated suite is always green, because the generator records the routine's current behaviour as the expected value and drops any test that will not pass cleanly. A failing test never appears in a first run. It appears later, when your code changes in a way that alters behaviour a test had pinned. That is what a regression test is for.