(with-redefs bindings & body)
binding => var-symbol temp-value-expr Temporarily redefines Vars while executing the body. The temp-value-exprs will be evaluated and each resulting value will replace in parallel the root value of its Var. After the body is executed, the root values of all the Vars will be set back to their old values. These temporary changes will be visible in all threads. Useful for mocking out functions during testing.
user=> [(type []) (class [])]
[clojure.lang.PersistentVector clojure.lang.PersistentVector]
user=> (with-redefs [type (constantly java.lang.String)
class (constantly 10)]
[(type [])
(class [])])
[java.lang.String 10]
(ns http)
(defn post [url]
{:body "Hello world"})
(ns app
(:require [clojure.test :refer [deftest is run-tests]]))
(deftest is-a-macro
(with-redefs [http/post (fn [url] {:body "Goodbye world"})]
(is (= {:body "Goodbye world"} (http/post "http://service.com/greet")))))
(run-tests) ;; test is passing
;; be careful, with-redefs can permanently change a var if applied concurrently:
user> (defn ten [] 10)
#'user/ten
user> (doall (pmap #(with-redefs [ten (fn [] %)] (ten)) (range 20 100)))
...
user> (ten)
79
;; redefine var
(def foo 1)
#'user/foo
(with-redefs [foo 2] foo)
2
;; redefine private var
(ns first)
(def ^:private foo 1)
#'first/foo
(ns second)
(with-redefs [first/foo 2] @#'first/foo)
2
;; @#' is the macros of (deref (var first/foo))
(with-redefs [first/foo 2] (deref (var first/foo))
2