Those of use that prefer to follow a BDD/TDD approach will have often sat back at certain times and revelled in smug self satisfaction as we congratulate ourselves on achieving on or above code coverage target, only to be felled soon after when a bug is reported against code you know to be covered 100%. TDD is great but there is a big difference between code coverage and use case coverage.
Writing unit tests to fail first is a highly recommended practice and it makes a lot of sense. However, I find more discipline is needed when you are investigating a bug report and you uncover the source of the problem. Especially if the code responsible is easy to fix and is already covered by unit tests. The temptation is to recognise the easy fix, apply it, and send it on its way in the interests of expedience. Knowing you have code coverage in that area and are likely to still succeed at any code quality gates, it’s understandable when the fix is a simple change, such as FirstOrDefault replacing SingleOrDefault, or a null coalescence injection to bypass an null reference exception.
But by doing this, you are then placing all the expectation back on to system or integration test to confirm your suspicion and confidence in the issue being resolved. And that could mean manual regression testing which is both expensive and still cannot guarantee they will cover the correct scenario.
By writing new tests that describe the reproduction steps before any other change and then executing those tests means you will have not only replicated the issue, but provided an automated safety check to continually verify whether or not the issue remain resolved.
It also challenges you to commit to an understanding of the issue as the test that you write should be the first part of code review after creating a pull request. This sort approach means you have two pairs of eyes on both the original issue raised and the interpretation of how that issue would surface.
For me, writing that first set of tests and then seeing them fail server to tell me I am more than halfway to resolving the issue because I’ve created the Quality Gate first, one that I know can be reviewed and automated. The team as a whole can then decide if further manual regression testing is required or if the consensus can allow a fix to be deployed.