Search code examples
clojure

How can I get multiple references to similar test fixtures


I'm creating a fixture to use in my tests. I bind the fixture to a dynamic symbol so that I can refer to it in my tests.

(def ^:dynamic *thing-doer* nil)

(defn with-thing-doer
  [config]
  (fn [f]
    (binding [*thing-doer* (create-thing-doer config)]
      (try
        (.start *thing-doer*)
        (f)
        (finally
          (.close *thing-doer*))))))

(use-fixtures :each
  (join-fixtures [(with-thing-doer a-config)]))

(deftest an-example-test
  (do-it! *thing-doer* thing)
  (is (= 1 (count (things-done)))))

This works great, but in some tests I need a few of these fixtures, with just slight differences between each. There are enough combinations that I don't want to create a separate dynamic symbol for each and every one. I'd rather that be defined in the test file that's setting up the fixtures. Something like:

(defn with-thing-doer
  [doer config]
  (fn [f]
    (binding [doer (create-thing-doer config)]
      (try
        (.start doer)
        (f)
        (finally
          (.close doer))))))

(def ^:dynamic *thing-doer-a* nil)
(def ^:dynamic *thing-doer-b* nil)

(use-fixtures :each
  (join-fixtures [(with-thing-doer *thing-doer-a* a-config)
                  (with-thing-doer *thing-doer-b* b-config)]

However it seems that the symbol given to binding needs to be known at compile time. Is there a way to do what I want, or a better approach I could take?


Solution

  • You can use with-bindings to create bindings dynamically. This way bound vars do not need to be known at compile time.

    Your with-thing-doer function would look like the following:

    (defn with-thing-doer
      [doer config]
      (assert (var? doer))
      (fn [f]
        (with-bindings {doer (create-thing-doer config)}
          (try
            (.start @doer)
            (f)
          (finally
            (.stop @doer))))))
    

    You need to pass the first parameter as a var object.

    (use-fixtures :each
      (join-fixtures [(with-thing-doer #'*thing-doer-a* a-config)
                      (with-thing-doer #'*thing-doer-b* b-config)]