Clojure - testing private vars


How do we test private vars in Clojure?

How do we write unit tests for private vars?

1. Namespace for implementation

One approach is just not to use private vars. Private vars are hidden, because they are part of the implementation of a functionality. As such, they are not part of the public API of the software, and should not be accessed from the outside world.

You could introduce a new namespace containing the implementation details. Lets call it yournamespace.impl. The name indicates that this namespace contains implementation only and it should not be relied on directly. You can unit test the vars if you define all vars publicly in this namespace.

2. Make private vars visible for testing

An other approach is to use Clojure’s dynamic nature. You can access the namespaces and define vars on the fly for testing:

(let [target (the-ns 'testable-namespace)]
  (doseq [[k v] (ns-map target)
          :when (and (var? v) (= target (.ns v)))]
    (eval `(defn ~(symbol (str "-" k)) [~'& args#] (apply (deref ~v) args#)))))

This code snippet checks all functions in the testable-namespace namespace and creates an alias for them in the current namespace. The aliases will have a - prefix and you can use these names from your unit tests.

For example, if you have the following in testable-namespace ns:

(defn- add [a b] (+ a b))

They you can test it like this in the unit test namespace.

(deftest test-add
  (is (= 5 (-add 2 3))))

Note that we needed to write -add instead of -add in the test.