Define the observable contract
A regression case preserves a behavior that previously failed so future changes cannot quietly reintroduce the defect. Start with the smallest input that distinguishes the incorrect behavior from the requirement, then write an independent expected result. This lesson intentionally includes an old broken search beside a corrected search for comparison. OldFind is not recommended production code. Its presence makes the historical defect visible: it stops before the final array position. The regression observation belongs to Find and a concrete expected index, not to an assumption that whatever the old function returned must define correctness.
Walk through the real program
The input array contains four at index zero and nine at index one. OldFind uses an upper loop limit of Length minus one, so it examines only index zero and returns negative one. The first output is old:-1. Find examines every valid index and returns one, producing fixed:1. Comparing that actual result with the independently written expected index one prints regression:PASS. The two-element input is enough to reveal this particular last-element defect without unrelated records, configuration, or random generation making the failure harder to understand.
Why the design is testable
A useful regression explains the cause rather than only preserving a screenshot. The requirement is first matching index, or negative one when no element matches. The original defect is the omitted last position. Once fixed, keep the minimal last-position example and add other contract cases as needed: first position, absence, empty input, and duplicates with the intended first-match behavior. A permanent test should not need to keep running the obsolete implementation. It should state the scenario and expected result clearly enough that future maintainers can understand why that case exists.
A boundary that matters
Do not derive the new expectation by calling another implementation that shares the same boundary mistake. Likewise, changing the expected index to negative one merely because a refactor currently returns it would erase the regression's purpose. A reported defect can also reveal a misunderstood requirement, so confirm the intended behavior before freezing a test. Keep historical context concise and factual. The strongest regression data is an informative input and a justified expected outcome, not a large pile of production data whose relevant difference nobody can identify.
Practice: isolate one behavior
First reduce the input to a single nine and predict that the broken search still misses it while Find returns zero. Hint: the only element is also the final element, making the omitted-boundary defect especially clear. Then test a target absent from the original two-element input and expect negative one from Find. Separate those scenarios so the absence contract does not hide a failure to inspect the last position. Preserve a name indicating which boundary the regression is intended to protect.
Practice: challenge another assumption
For another exercise, add duplicate nines and define whether Find should return the first match or any match. Hint: the current linear implementation promises the first encountered index, so write that expectation explicitly. Introduce a deliberately wrong reverse search and confirm which case rejects it. Then move the regression into a genuine framework project without keeping OldFind in the production library. The test should continue to explain the defect through its input and assertion rather than through dependence on broken code executing beside the fix.
Review the evidence
The baseline separates a historical observation, a corrected result, and a real expected-value comparison. That distinction prevents a demonstration from becoming a self-referential test. Regression work is successful when the suite would fail if the old mistake returned while remaining stable under harmless refactoring. Keep the case small, retain its contractual reason, and use additional cases for separate obligations instead of expanding one regression until it accidentally tests an entire application workflow. A precise counterexample is durable evidence that others can understand and rerun.
- The old function is intentionally defective and labeled accordingly.
- The corrected last-element result is checked against the literal index one.
- A regression should remain understandable without executing obsolete code.
A working example
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
int OldFind(int[] values, int target)
{
for (int i = 0; i < values.Length - 1; i++) if (values[i] == target) return i;
return -1;
}
int Find(int[] values, int target)
{
for (int i = 0; i < values.Length; i++) if (values[i] == target) return i;
return -1;
}
int[] input = { 4, 9 };
Console.WriteLine($"old:{OldFind(input, 9)}");
int actual = Find(input, 9);
Console.WriteLine($"fixed:{actual}");
Console.WriteLine(actual == 1 ? "regression:PASS" : "regression:FAIL");
Expected output
old:-1 fixed:1 regression:PASS
The intentionally broken old function demonstrates the defect; the expected index is written independently.