Unit testing improves designs by making the costs of bad design explicit to the programmer as the software is written. Complicated software with low cohesion and tight coupling requires more tests than simple software with high cohesion and loose coupling. Without unit tests, the costs of the poor design are borne by QA, operators, and customers. With unit tests, the costs are borne by the programmers. Unit tests require time and effort to write, and at their best programmers are lazy and proud folk. They don't want to spend time writing needless tests.
Unit tests make low cohesion visible through the costs of test setup. Low cohesion increases the number of setup tasks performed in a test. In a functionally cohesive module, it is usually only necessary to set up a few different sets of test conditions. The code to set up such a condition is called a test fixture. In a random or functionally cohesive module, many more fixtures are required by comparison. Each fixture is code that must be written, and time and effort must be expended.
The more dependencies on external modules, the more setup is required for tests, and the more tests must be written. Each different class of inputs has to be tested, and each different class of input is yet another test to be written.
Jeff Younker (Foundations of Agile Python Development, Apress, 2008, pages 141 - 142).
Never have I seen the case for unit testing and TDD put better.