“As a quality assurance specialist I was the customers advocate. As a malpractice attorney specializing in software, I am still the customer’s advocate but in a different arena and profession.”
--borrowing a turn of phrase from Susan A. Capra
People can follow and remember simple rules. Write unit tests to cover 100% of the lines of code that are written. So, simple. So, understandable. And, there are tools that will measure coverage for you. I will begin with some of the comical arguments against, and finish with the arguments for code coverage.
Arguments Against Unit Testing to Coverage
The first argument is we don’t have enough time. If you don’t have enough time to write tests, how are you going to have enough time to fix bugs? There are always bugs. If you don’t have enough time then either the schedule is wrong or too much technical debt (entropy) is being created. Without unit tests to code coverage, you can’t safely refactor. If you can’t refactor then you can’t mitigate entropy.
It isn’t possible to get 100% coverage with unit tests. If it is possible to write the code then its possible to test the code. If a test can’t be written then either the code is not understood or the code is not needed. There are testing tools for every layer of architecture.
UI/UX’s cannot be tested. There are a zillion tests libraries for testing client-side code: Jest, Mocha, Chai, QUnit, Vite, and so may other tools.
Integration tests are too expensive or time consuming. There are several mocking libraries like JustMock. You can also use backup and restore or scripts to stage your test database. Include a reset strategy for the back end. If you are using a service then mock the service.
Database testing isn’t supported. MS SQL Server has SSDT for database testing. You can also simply write coded database tests. With old UDB stored procedures were written in C, so writing coded database tests made sense.
Testing is for edge cases and functional behavior. 2Testing is for everything. It may be very difficult to guess the edge cases. The edge cases may never happen. When an edge case occurs you add a unit test for that, redesign the offending algorithm and it never happens again. Edge case closed.
If we change the behavior then we’ll have to re-write the tests. Precisely. If you change behavior the old tests may not cover anything. So, write the new tests and get back to coverage.
Recommended by LinkedIn
Sane Reasons to Test to Code Coverage
Put the brakes on trace bias testing. Without a simple, iron rule like testing to 100% code coverage the average programmer will test with a trace bias. Trace bias is designed to affirm what one wants to be true. With code coverage it is necessary to test the success and failure path.
Teaches programmers to write better code. The other thing code coverage testing does is it penalizes those writing “big balls of mud” and “spaghetti code”. It is very difficult to get to code coverage the code is horrible.
Encourages good metrics. If your metrics are horrible then testing is to coverage becomes very difficult. Metrics include cyclomatic complexity (branch statements), lines of code (a likely violation of the single responsibility principle (SRP)), maintenance complexity (overall measure of entropy) and computational complexity (algorithms with a nasty Big-O).
As a general rule you must have at least one test for every branch. Write a method with 15 branches and you’ll end up writing at least 15 tests for that function.
You’ll save money and preserve goodwill and customer affinity. If you don’t test to coverage, you’ll have a nasty surprise eventually. If you missed an edge case the discipline of coverage will close it quickly, let you run tests—thousands in minutes—and re-deploy with the knowledge that you haven’t cause multiple regression errors.
You’ll save money because you will have fewer bug fixes, fewer catastrophic failures, and bug fixes cost disproportionately higher than writing code.
To sum up: You want programmers to write code that follows things like SOLID principles. This requires a disciplined practice. Part of any disciplined practice is to test what you’ve written before doing a pull request. Part of any disciplined practice is the one that created the mess is responsible for cleaning it up.
Adding 100% code coverage to your practice means ultimately programmers will code better, create less technical debt, and projects will begin to come in ahead of schedule and under budget.
Paul Kimmel is a software architect who specializes in building teams and solid software and has delivered software on most of the computer platforms still in existence.