Sure, let's say you're writing a web app that at some point needs to look up users by id and password. You could implement this as a function:
(defn get-user [db id pw]
...query the db...)
But the problem as you've noticed is that it's hard to test this function, because you have to somehow either actually hit a database during a test, or you have to redef the function. Instead I say we should make formal contracts in our applications. So we'd implement a protocol:
(defprotocol IDb
(get-user [this id pw]))
(deftype MainDBInterface [db-conn]
IDb
(get-user [this id pw]
...))
Now it's trivial to stub out the database with something that provides a mock DB:
(defn mock-db [ids-and-pw]
(reify IDb
(get-user [this id pw]
(= pw (get ids-and-pw id)))))
So what we've done here is taken a implicit contract "get-user" and made it explicit "IDb". Now if we need to go and implement a new database, or port this project to run on a different platform we know exactly where we need to go to do our porting.