We know that tests result in better code. They also result in better programmers.
The first implementation of a project will often be utilitarian, complying with the edict of “just get it working”. Code will be written and tweaked until the tests pass, but there are few cycles, if any, devoted to refining the code to be higher quality. This the red/green/refactor cycle is limited to just red and green.
The refactoring phase is where the code goes from simply working to being well-crafted. As the mindset of the programmer changes from being focused on utility to being focused on quality, they program accordingly different.
With the principle of quality being foremost, and with the confidence from having a thorough set of tests, the programmer can also push the boundaries of their knowledge, such as delving into advanced object-oriented programming and metaprogramming, which can be dauntingly complex and risky. Those areas do not necessary have an immediate impact on functionality, so when a programmer is in functionality/utility mode, they’re less likely to employ those techniques. However, in quality mode, a programmer will feel more justified, and confident, in using those techniques, which over the long term can cause a dramatic improvement to a project.
Often forgotten is that both code and tests should be refactored. Test code that is unclear, misleading, or just wrong can be very frustrating to someone trying to understand a body of code, since the tests are the best starting point.
The bottom line is that programmers must understand that testing includes refactoring (including of the test code itself), and that the refactoring phase is where programmers, and projects, can become vastly better.