unit-testingclojureclojure.test

In clojure test, how to mock out multiple methods when testing one function?


I am writing a clojure.test unit test for a rather large function in my application. This function makes several calls to db and external REST services and does some computation. for example, my function to be tested is like so

(defn myfunc [id]
   (let[
        w (some-security-call id)
        x (some-db-call id)
        y  (some-REST-call x)
        z ( some-audit-call y)

       ]
       (-> y :somekey )))

for the purpose of testing this method, I want to stub out or redefine "some-audit-call" and "some-security-call". Clojure's with-redefs-fn only redefines one method at one time.

Is there a standad way to mock out multiple functions used in a function being unit tested?


Solution

  • with-redefs works on as many functions as you want. Here is a redacted example from my actual production tests.

    (with-redefs [namespace/redacted            (constantly [])
                  namespace/redacted                 (fn [& args] (async/go namespace/redacted))
                  namespace/redacted        (constantly [2 4])
                  namespace/redacted                (fn [& args] (namespace/redacted sample-redacted-ads))
                  namespace/redacted                (fn [_ _ redacted & _]
                                                      (async/go (cond-> namespace/redacted
                                                                  namespace/redacted (dissoc redacted))))
                  namespace/redacted                   (fn [& args] (async/go nil))
                  namespace/redacted       fake-redacted
                  namespace/redacted       fake-redacted
                  namespace/redacted      namespace/redacted
                  namespace/redacted       (go (constantly []))
                  namespace/redacted               (fn [_] [])
                  namespace/redacted      namespace/redacted
                  namespace/redacted      namespace/redacted
                  namespace/redacted                        (fn [_] {:redacted "redacted"})]
      (is (= "redacted"
             (get-in (<!!
                      )
                     ))
          "We should return the redacted if we don't pass it in")
      ... many more tests here ...
    
    )
    

    if you need to redefine a function that is used by another function that you want to redefine then you have to nest the calls to with-redef. this sometimes causes people to think that with-redefs only works with one function.

    You likely don't want to use with-redefs-fn unless you know you have a specific reason.