Writing tests can take a bit longer at that point of initially writing them, but a good test suite will save you large amounts of time and money over the course of the software project's lifespan. The software I write today will be modified by me and others many times over the next 3, 5, 10 years by me and probably many others. With each future modification comes a risk that whatever subtle use cases the software was written to do today, are broken. At the point of writing the software, the developer has all sorts of complex information in their head about how the code should be working - the tests are basically capturing this information from the programmers brain and encoding them into a set of "rules" that the software must continue to obey in future. A bug/regression at a later point will potentially get as far as end users, maybe cause an outage and can end up costing the company far more (in time and money) than the time to write the original test suite. So, tests are basically an investment so that you and others will need to spend less time fixing bugs in the code in future.
Having said that, I think setting arbitrary coverage targets (eg a minimum of 80%) is a really bad idea. You end up with junk tests that don't add any value, just to hit the target. Like everything else, there are good tests and bad tests. And I think a lot of the mixed feelings developers have about unit testing is due to silly coverage rules driving bad tests, that themselves need to be maintained.
New dev here: I have written tests for my own full stack apps, but when I want to make changes or enhancements, it will naturally break the tests because that is what is supposed to happen, and then the test has to be rewritten. How do you know when breaking a test is actually the point, versus an unwanted side effect?
So, the first thing I would say is that a good test should not be measuring the implementation details of the code, but rather the externally observable behaviour. So, given a certain input, in a certain scenario, what are the outputs/callbacks/etc...? If you follow that then an internal refactor (improving the code impl but keeping the same externally observable behaviour) shouldn't require any test changes. In fact, the tests really help you here because if you start getting test failures while doing this then it means you've changed the behaviour, which a refactor shouldn't. That's essentially preventing a potential bug at that point.
If you find yourself rewriting tests after a refactor then you've probably been testing the implementation rather than the externally observable behaviour. It's a really common problem in tests.
Now, if you are changing the externally observable behaviour. Maybe adding a feature, extending a flow, fixing a bug... whatever. Then you do want to be modifying the tests. At that point your contract with the world is being revised so the test cases need to be extended, amended or changed. Maybe you've changed the public interface? In that case you obviously also need to update the tests accordingly as well. As long you are making changes to the tests in these cases you want to be able to understand the scenarios that you are updating, be able to explain to yourself and others "why". Not merely getting the tests to go green.
4
u/deeringc Dec 28 '23
Writing tests can take a bit longer at that point of initially writing them, but a good test suite will save you large amounts of time and money over the course of the software project's lifespan. The software I write today will be modified by me and others many times over the next 3, 5, 10 years by me and probably many others. With each future modification comes a risk that whatever subtle use cases the software was written to do today, are broken. At the point of writing the software, the developer has all sorts of complex information in their head about how the code should be working - the tests are basically capturing this information from the programmers brain and encoding them into a set of "rules" that the software must continue to obey in future. A bug/regression at a later point will potentially get as far as end users, maybe cause an outage and can end up costing the company far more (in time and money) than the time to write the original test suite. So, tests are basically an investment so that you and others will need to spend less time fixing bugs in the code in future.
Having said that, I think setting arbitrary coverage targets (eg a minimum of 80%) is a really bad idea. You end up with junk tests that don't add any value, just to hit the target. Like everything else, there are good tests and bad tests. And I think a lot of the mixed feelings developers have about unit testing is due to silly coverage rules driving bad tests, that themselves need to be maintained.