I've noticed a small disagreement in the Agile world around the "true purpose" of unit tests? Mostly the two camps are "to catch mistakes" and "to direct design". I want to explore these ideas a bit further. Arlo Belshee gathered a bunch of great perspectives at What Makes a Good Test Suite?, and part of what I'm doing here is reorganizing those ideas, especially Llewellyn Falco's answer.
Value #1: Bugs.
Bugs ruin software, nullifying the value we work so hard to create. Tests catch bugs (sometimes called "checking" or "regression" or "validation"), so our users and our reputations are not harmed. If another person (or my future self) works on this code later on, I count on tests to catch mistakes before our customers do.
Having tests means I can refactor safely (for some definitions of refactoring). Refactoring makes future work easier. Programmers are happier. We can say "yes" to our customers more often. When refactoring, tests are especially important in languages without great refactoring tools (basically everything except C# and Java).
Speed matters. Faster tests => I run them more often => less has changed since the last run, and what has changed in fresh in my brain => easy to understand what a failure means.
Granularity matters. When a test fails, a granular test will tell me what is broken without a lot of investigation. (Some tests can also provide good diagnostics around a failure, which helps in similar ways.)
Reliability matters. If tests are flaky or broken, you either ignore them (so they deliver 0 value) or you rerun them (which acts as a multiplier on runtime).
Coverage matters. Luckily, strictly following TDD means you won't write any untested code, so you can be confident in your coverage, which is especially important in manual refactoring. Sticking with TDD requires discipline.
When I do find a bug, the responsible thing to do is add a test for it when I fix it. Now I can be sure I'll never have that bug again.
In this mindset, mocks are a great tool, because they let me unit test my code in isolation, which makes them faster, more reliable, and easier to write. I'm likely to introduce indirection ("program to interfaces") and use dependency injection, and maybe even the Service Locator pattern.
You only get this value if the have the right tests.
The bug-catching value appears when tests are run.