Scenario 1. A developer writes the code and some unit tests, then submits it to integration and receives a report that the coverage of his tests is low. He writes code to fix it.
Scenario 2. A developer writes the code and some unit tests. The unit tests test the functionality as implemented. He receives the report that the coverage is low. He writes more tests cover some corner case he missed in the first place.
Scenario 3. The developer writes the unit tests to cover a given functionality, then writes the code to execute the functionality. He receives the same report as the others, and removes dead code from the functionality.
The stories above represent three scenarios in which unit testing production falls.
The first one is the weekend project: write the code and hope for the best. This is clearly bad, because it show a lack of planning, and a disregard for real quality.
The second is the post production test: the developer writes the functionality and then writes the test according to what he wrote. This a a pernicious pattern of work, because it assumes that the code implements the specification correctly. Sometimes it does, but the pattern will not find when it doesn’t.
The third pattern is correct. The tests form the semi-formal specification of the functionality, and the code is written to reflect it – the tests will detect if it doesn’t.
The stories above also show the way code coverage is seen in each tier. In the first scenario, the code coverage is seen as something to be achieved. It’s usually seen as a burden that the developer must endure, something that hinders his productivity but is required from his manager and comes from the developers overconfidence or immaturity (it’s fine to be immature if you’re just came out the university gates – senior developers exist to guide you).
The second and third see code coverage as a source of improvement. The second sees it as a way to improve the testing. The third sees it as way to improve what’s being produced.
Overall, the third mode leads to improvement in quality, the second guarantees that the functionality doesn’t change unexpectedly during maintenance, and the first one leads to none of those – to be fair, it at least improves the chances that crashes don’t happen.