在 leiningen 插件中使用动态变量绑定

Using a dynamic variable binding in a leiningen plugin

我有一个 lein 插件,可以手动 运行 我的 clojure.test 代码。它声明了一个我希望从测试中访问的动态变量 baseuri。我将剥离并更改代码以直截了当。在这里,在我的插件中,我有一个配置文件,它创建动态 baseuri 变量并将其设置为空字符串。

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

插件中的任务设置动态 baseuri 变量和 运行s 测试 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)
  ))

在我的 clojure.test 中,我尝试使用 baseuri 变量,但绑定不成立。它的值是我最初声明的 baseuri 是(一个空字符串)

;; 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

我编辑了代码,以基本方式显示 clojure.test 个案例 运行。我只是将我想成为 运行 的命名空间传递给 clojure.test/run-tests 方法。

也许您出于非常具体的原因有一个动态变量,但是,由于您没有明确说明,我在这里试一试。

避免动态重新绑定变量。在最好的情况下,完全避免全局状态,而是重新定义您的函数以将 baseuri 作为参数。
或者重构您的应用程序,使其完全不需要静态变量,就像您现在拥有的那样。

编辑 我猜你的功能是:

(defn run [project]
  (binding [config/baseuri "https://google.com/"]
    (println config/baseuri) ;; <-- prints google url
    ;; runs clojure.test code here …
  ))

(deftest sampletest
  (println config/baseuri))

没有以任何方式连接。至少我不明白他们应该如何。你是 运行 一个测试并打印一些其他变量而不重新绑定它。
也许您可以将 link 添加到 repo 到最小的可重现测试用例以更好地理解它?

我同意 clojure.test 在参数化测试方面实施不是最佳的。

我不确定为什么您的 binding 表单不起作用 - 我已经检查了 clojure.test 中的代码,但我看不出哪里出了问题。我会检查是否:

  • 测试在与 binding 建立相同的线程中执行(也许您可以在插件和测试中添加记录线程 name/id)

  • 不同的 class 加载程序导致您的插件命名空间及其全局动态变量实际上被加载和定义了两次

我还有一个想法(我真的不想批评你的解决方案,只是想找到替代解决方案:)):你的问题是从外部源向你的测试代码传递一个全局配置选项像测试脚本配置。您是否考虑过将它们作为环境变量传递?您可以使用 (System/getenv "baseuri")environ.

轻松阅读它们