DEV Community

Marx Jenes
Marx Jenes

Posted on

Regression Test That Would Have Caught It, If Anyone Had Written It

We fixed a discount-stacking bug once - a promo code and a loyalty discount were combining in a way finance definitely hadn't approved - shipped the fix, closed the ticket, moved on to the next sprint. Eleven months later, a refactor of the pricing service reintroduced the exact same bug. Same root cause, same wrong output, same customers getting a discount they shouldn't have. Nobody on the team remembered the first incident. The person who fixed it originally had left the company. The only record that it had ever happened was a closed Jira ticket nobody thought to search before merging the refactor.

That's the entire argument for regression testing in one story, and it's a much narrower argument than "run the tests again before release." A regression test isn't a general-purpose safety net. It's a specific, permanent record that says: this exact thing broke once, here's proof it's not allowed to break the same way again.

Why the fix alone was never enough

Fixing a bug closes the incident. It doesn't prevent the next person from reintroducing it, because a fix by itself leaves no trace in the codebase that says why the old behavior was wrong. Six months later, someone refactoring that code has no way of knowing a previous version of this exact logic caused a real problem - they just see code that looks reasonable, changes it in a way that looks reasonable, and ships it.

A regression test is what turns "we fixed this" into "this can't happen again without someone finding out immediately." It's not really about testing in the abstract sense. It's closer to institutional memory that runs in CI instead of living in a person's head, which is exactly why it survives someone leaving the team and a ticket getting buried in a backlog nobody searches.

Why it gets skipped anyway

Nobody skips this step because they don't understand its value. They skip it because writing the regression test is extra work at the exact moment the incident feels resolved - the fix is deployed, the customer's been refunded, everyone wants to move on to whatever got deprioritized while the fire was being put out. Writing a test that specifically encodes "promo codes plus loyalty discounts shouldn't stack past X%" takes real thought: what's the minimal case that reproduces it, what's the assertion, does it need its own fixture or does it fit into an existing suite.

Under deadline pressure, that thirty minutes loses to whatever's next on the sprint board almost every time. The bug gets fixed. The proof that it was ever a bug doesn't get written down anywhere durable. This is an extremely normal way for teams to operate, and it's also exactly how the same bug comes back a year later wearing a different diff.

What actually closes the gap

The teams that do this well tend to treat "write the regression test" as part of the incident's definition of done, not an optional follow-up. Not every bug fix needs one - a typo in an error message doesn't need a permanent regression test guarding it forever - but anything involving money, data correctness, security, or a customer-facing failure earns one as a rule, no exceptions for how busy the sprint is.

The other thing that helps, less obvious but just as important: the regression test should be built from what actually happened, not a cleaned-up, idealized version of it. If the real bug involved a specific combination of a promo code, a loyalty tier, and a checkout retry after a timeout, the test should reproduce that specific combination, not a simplified "discounts shouldn't exceed X%" check that misses the exact conditions that caused the real failure. A regression test that tests a simplified version of the bug can pass while the actual bug is still very much alive.

This is where a lot of regression suites quietly lose their value over time - not because nobody's writing tests, but because the tests that do get written are approximations of the incident rather than reconstructions of it, written from memory a few days later instead of from what actually happened on the wire when it broke.

The suite that actually earns trust

A regression suite built this way - one entry per real incident, grounded in what genuinely happened, added as a non-negotiable step rather than a someday task - becomes something a team actually trusts, because every test in it has a story behind it. Not "we thought this might be a problem," but "this exact thing happened, and here's the proof it can't happen silently again."

The discount bug that came back eleven months later wasn't a failure of testing philosophy. It was a gap between "we fixed it" and "we made sure it can't happen again the same way," and that gap is exactly where regression testing is supposed to live. Closing it takes thirty minutes at the time it's most annoying to spend them. Not closing it costs a lot more than thirty minutes, just later, and usually to someone who wasn't even there the first time.

Top comments (0)