Concepts / Designing Test Cases for Generated Code

Designing Test Cases for Generated Code

Functional correctness asks what the code does, measured against what it was supposed to do. Style, readability, and plausibility are separate qualities and do not answer that question.

  • Programming

The First Question About Generated Code

When a model generates code, it is tempting to ask whether the code looks reasonable. Clean indentation, sensible variable names, and a plausible structure all feel like signs of success. The source is clear that this is not the first question to ask. The first question is whether the code does what it was supposed to do.

What do you think happens?

A generated function looks clean, reads well, and runs without raising an error. Is that enough to call it correct?

  • Yes, because clean code that runs is correct code

  • No, because correctness is judged by whether its output matches what it should produce

Reveal answer
Answer:

No, because correctness is judged by whether its output matches what it should produce

Code can look reasonable and run without error while still returning the wrong answer. The check that matters is whether the actual output agrees with the expected output for each input.

The same idea applies beyond code. If you ask a model to build a website, you check whether the website meets your requirements. If you ask it to make a restaurant reservation, you check whether the reservation succeeds. In each case the evaluation is based on behavior, not appearance. This article focuses on the code case, because there functional correctness can be measured automatically.

Functional Correctness as the Ultimate Metric

Definition

Functional correctness measures whether code performs its intended functionality. It is treated as the ultimate metric for evaluating an application, because every other property of the application matters only insofar as the application does its job.

Functional correctness is not a new idea created for AI. Long before AI was used to write code, automatically verifying functional correctness was standard practice in software engineering. Coding platforms such as LeetCode and HackerRank use functional correctness evaluation to validate submitted solutions. A submission is accepted or rejected based on whether it produces the right results, not on how it reads.

Key point

Functional correctness asks what the code does, measured against what it was supposed to do. Style, readability, and plausibility are separate qualities and do not answer that question.

Two Stages of Checking Generated Code

A measurement of functional correctness has two stages, and they answer two different questions. The generated code is first passed to a Python interpreter to check whether it is valid. Only if it is valid does the second question arise: for a given input pair, does the code output the correct result?

  1. 1
    Stage one: give the generated code to the Python interpreter and confirm that it is valid Python.
  2. 2
    Stage two: for each input pair, run the function and compare its output with the expected output.
  3. 3
    Record the result of every comparison so that the report shows exactly where the function agreed or disagreed with expectations.

Tracing a Checking Program

Consider a checking program that tests a generated gcd function against a list of input pairs. Each pair comes with an expected greatest common divisor. The program prints one line per pair and labels each mismatch with the expected value and the value the function actually produced. Before you read the output, think about what the report will contain.

python
Output (expected)
FAIL (15, 20): expected 5, got 15
PASS (9, 9): expected 9, got 9
FAIL (12, 18): expected 6, got 12
FAIL (7, 3): expected 1, got 3
Notes on the code
  • The function gcd is the generated code under test.
  • test_pairs holds one test case per tuple: two inputs and the expected output.
  • The loop runs the same comparison for every test case.

What do you think happens?

Before reading the output below, predict which of the four test cases will print PASS and which will print FAIL.

Reveal answer
Answer:

Only the pair (9, 9) prints PASS. The pairs (15, 20), (12, 18), and (7, 3) print FAIL.

The function returns the smaller input. For (9, 9) the smaller input is 9, which matches the expected value. For (15, 20) it returns 15 instead of 5, for (12, 18) it returns 12 instead of 6, and for (7, 3) it returns 3 instead of 1.

Read the report line by line. Each line beginning with FAIL names one input pair, then states the expected value and the value the function produced. The line FAIL (15, 20): expected 5, got 15 is the mismatch the source describes. The correct greatest common divisor of 15 and 20 is 5, so a function that returns anything else for that pair is wrong. The report shows exactly where the function diverged from the expected result, which is the information a developer needs in order to debug it.

Test caseinput pair and expectedvalueGenerated functionreceives the input, returnsactual valueActual equalsexpected?comparison stepPASSNext test casesame flow repeatsFAILreport expected and actualvaluesinputactual valueequalnot equalrecordrecordrepeat for each case
What happens step by step when the harness calls the generated function, and how it decides between PASS and FAIL?

Follow one test through the flowchart. The test case supplies an input pair and an expected value. The generated function receives the input and returns an actual value. The comparison step then sends the flow to one of two terminal results. The same flow repeats for every test case in the set. This is why a single function can produce several FAIL lines in one report.

Anatomy of a Test Case

A unit test executes code in a scenario and compares the actual output to the expected output. A test case is therefore a scenario plus its expected output. The scenario is the input the code receives, and the expected output is the value that code must return for that input. Neither part is useful alone: a scenario without an expected output has nothing to check against, and an expected output without a scenario does not say what was being tested.

gcd(15, 20)scenario: the input thefunction receives5expected output: the valueit must returnchecked against
What are the parts of a single test case, and how do the input scenario and the expected output relate to each other?
Worked example

Writing One Test Case from a Requirement

The requirement is that gcd(15, 20) must return the greatest common divisor of 15 and 20. Write the test case.

  1. 1
    Identify the scenario

    The scenario is the input the function receives: the call gcd(15, 20).

  2. 2
    Identify the expected output

    The greatest common divisor of 15 and 20 is 5, so the expected output is 5.

  3. 3
    Combine them

    The test case is the scenario plus its expected output: (15, 20) paired with 5.

Result

The test case (15, 20) -> 5. When the harness runs the generated function on (15, 20) and gets 15, the comparison fails and the report shows FAIL (15, 20): expected 5, got 15.

From Many Tests to One Correctness Result

A single test case tells you about one input. Code is typically validated with unit tests, in which the code is executed in different scenarios to ensure that it generates the expected outputs. Each scenario is one test, and the whole set of scenarios is what gives a measurement of functional correctness its coverage. A function that passes one test but fails many others is not functionally correct for the intended behavior.

Generated codeoutput of the modelValidity checkPython interpreterTest suiteone test case per scenarioPass or fail per testactual compared withexpectedCorrectness resultoverall measure from alltest resultsmust be validif valideach testaggregated
How does generated code move through the test suite to become a pass/fail result and an overall correctness score?

Benchmarks That Use Functional Correctness

Benchmarks are standardized datasets and metrics used to evaluate AI models on code generation tasks. A benchmark problem comes with a set of test cases, and the generated output is checked against those test cases. The source gives an example from HumanEval, a benchmark from OpenAI: a problem asks for a function named has_close_elements, which takes a list of floating-point numbers and a threshold. The problem description includes example calls, and each test case pairs one scenario with the output the function should return for it. The test cases are what the generated function is checked against.

BenchmarkWhat it evaluatesHow correctness is checked
HumanEvalPython code generation from problem descriptionsFunctional correctness, using the benchmark's test cases
MBPP (Mostly Basic Python Problems Dataset)Python code generation from basic programming problemsFunctional correctness, using the benchmark's test cases
SpiderText-to-SQL: SQL queries generated from natural languageFunctional correctness, using the benchmark's test cases
BIRD-SQLText-to-SQL: SQL queries generated from natural languageFunctional correctness, using the benchmark's test cases
WikiSQLText-to-SQL: SQL queries generated from natural languageFunctional correctness, using the benchmark's test cases

Benchmarks named in the source all use functional correctness as their metric, even though they generate different kinds of output.

The same measurement idea extends beyond Python. Spider, BIRD-SQL, and WikiSQL are benchmarks for text-to-SQL, where the generated output is a SQL query. Their test cases decide whether the generated output is accepted, just as the Python benchmarks' test cases do. What changes between benchmarks is the kind of output produced, not the principle of checking that output against expected results.

Mistakes When Designing Tests

  • Common mistake

    Treating a clean, readable function as a correct one

    What it looks like

    A generated gcd function is well formatted, so it is accepted without running any test.

    Why it fails

    Functional correctness is about whether the output matches the intended behavior. Appearance does not measure that.

    Do this instead

    Run the function against test cases with expected outputs and let the results decide.

  • Common mistake

    Treating a successful run as a passing result

    What it looks like

    The gcd function runs for (15, 20) without raising an error, so the developer assumes it works.

    Why it fails

    The function returns 15 for that pair, while the expected value is 5. No error was raised, but the answer is wrong.

    Do this instead

    Compare the actual output with the expected output for every input pair, after confirming the code is valid.

  • Common mistake

    Writing only one test case

    Why it fails

    A single scenario covers a single input. The coverage of a functional correctness measurement comes from the whole set of scenarios.

    Do this instead

    Write several scenarios that exercise different inputs, including ones where a wrong function would be exposed.

  • Common mistake

    Writing an expected output without a scenario, or a scenario without an expected output

    Why it fails

    A test case is a scenario plus its expected output. Without both parts there is nothing to execute or nothing to compare against.

    Do this instead

    Always pair the input the code receives with the exact value it must return.

Practice: Reading a Different Harness Report

MEDIUM

Suppose a generated function is written as return max(a, b) instead of return min(a, b), and it is run against the same test_pairs list used earlier: (15, 20, 5), (9, 9, 9), (12, 18, 6), and (7, 3, 1). Predict which lines of the report will begin with FAIL and what each FAIL line will say. Then check your answer by tracing each pair through the harness flowchart.

Hints
  • For each pair, work out what max(a, b) returns before comparing it to the expected value.
  • Ask whether the returned value equals the expected value for each of the four tuples.
  • Pay attention to the pair where both inputs are equal: when a equals b, max and min return the same value.
EASY

Write one new test case for a gcd function. Give the scenario (the input pair) and the expected output, then state which of the two parts a harness would need in order to produce a PASS or FAIL line.

Hints
  • Choose a pair whose greatest common divisor you can verify by hand.
  • A test case needs both the input the function receives and the value it must return.

Key Takeaways from Test Design

  1. 1
    Functional correctness measures whether code performs its intended functionality, and it is the ultimate metric for evaluating an application.
  2. 2
    Generated code is checked in two stages: first for validity with a Python interpreter, then for whether its output matches the expected output for each input.
  3. 3
    A test case is a scenario plus its expected output, and a test harness reports PASS or FAIL for each case by comparing actual results with expected results.
  4. 4
    Benchmarks such as HumanEval, MBPP, Spider, BIRD-SQL, and WikiSQL use functional correctness as their metric to evaluate AI code generation.

At a glance

  • Functional correctness measures whether code performs its intended functionality and is the ultimate metric for evaluating an application.
  • Generated code is checked in two stages: validity first, then whether its output matches the expected output for each input.
  • A test case is a scenario plus its expected output, and a harness reports PASS or FAIL by comparing actual with expected results.
  • HumanEval, MBPP, Spider, BIRD-SQL, and WikiSQL all use functional correctness as their metric for evaluating AI code generation.

Related concepts

More concepts starting with D