That's the original purpose of mock objects - we go contract-first, defining how a module will be used before considering how it will work.
On real-world systems, we typically end up with a small ratio of abstractions and mocks to concrete implementations - just the key high-level interactions