Search code examples
pluginsclojureleiningenclojure.test

Using a dynamic variable binding in a leiningen plugin


I’ve got a lein plugin that manually runs my clojure.test code. It declares a dynamic variable baseuri that I wish to access from within my tests. I’ll strip out and change the code to get straight to the point. Here, inside of my plugin, I have a config file that creates the dynamic baseuri variable and sets it to a blank string.

;; myplugin
;; src/myplugin/config.clj
(ns leiningen.myplugin.config)    
(def ^:dynamic baseuri "")

A task from within the plugin sets the dynamic baseuri variable and runs tests with clojure.test:

;; src/myplugin/runtests.clj
(ns leiningen.myplugin.runtests
      (:require [leiningen.myplugin.config :as config]
                [clojure.test]
                [e2e.sometest]))

(defn run [project]
  (binding [config/baseuri "https://google.com/"]
    (println config/baseuri) ;; <-- prints google url
    ;; run clojure.test test cases from e2e.sometest namespace
    ;; This will call the `sampletest` test case
    (clojure.test/run-tests e2e.sometest)
  ))

And inside of my clojure.test I try to use the baseuri variable but the binding doesn’t hold. It’s value is what I originally declared baseuri to be (an empty string)

;; tests/e2e/sometest.clj
(ns e2e.sometest
  (:require [leiningen.myplugin.config :as config]))

(deftest sampletest
  (println config/baseuri))  ;; <-- Prints an empty string instead of google url

I've edited the code to show in a basic manner how the clojure.test cases are run. I simply pass in the namespace I want to be run to the clojure.test/run-tests method.


Solution

  • I agree that clojure.test implementation is not optimal when it comes to parameterising your tests.

    I am not sure why your binding form doesn't work - I have checked the code in clojure.test and I cannot see what could be wrong. I would check if:

    • the tests get executed in the same thread as the binding is established (maybe you could add logging the thread name/id in your plugin and in your tests)

    • different class loaders causing that your plugin namespace and its global dynamic variable is actually loaded and defined twice

    I have one more idea (and I really don't want to criticise your solution, just trying to find alternative solutions :)): your problem is to pass a global configuration options to your code under test from external sources like test scripts configuration. Have you thought about passing them as environment variables? You could easily read them using (System/getenv "baseuri") or environ.