重用相同的 let 绑定

Reusing the same let bindings

我正在为 clojure 应用程序重构我的测试套件,并试图弄清楚是否有一种方法可以保存 let 绑定以供重用以最大限度地减少复制代码,因为许多测试需要类似的设置但会相互干扰并要求自己最熟练。理想情况下,我希望它能像这样工作:

(def let-bindings [bind1 val1 bind2 val2 bind3 val3])

(deftest test-1
  (testing "my test"
    (let (conj let-bindings [bind4 val4])
      ...)))

(deftest test-2
  (testing "my second test"
    (let (conj let-bindings [bind5 val5])
      ...)))

为了进一步说明,我需要在测试中评估 val1 和 val2,而不是在定义 let 绑定时,因为调用影响测试数据库的方式需要在每次测试后重置。这是否意味着我需要一个宏?

let 是一种特殊的形式,因此尝试对其进行元编程而不在宏中执行它是行不通的。也许您应该只定义通用绑定:

(def bind1 val1) 
(def bind2 val2) 
(def bind3 val3)

(deftest test-1
  (testing "my test"
    (let [bind4 val4]
      ;; here bind1...bind4 would be available
      ...)))

...

编辑

以下是我想象中您可以使用宏实现的方式:

;; notice that the let will be recreated each time so if
;; val1 ... are computational hard consider caching. 
(defmacro elet [ bindings & body ] 
  `(let [bind1 val1 bind2 val2 bind3 val3 ~@bindings] 
     ~@body))

(deftest test-1
  (testing "my test"
    (elet [bind4 val4]
      ;; here bind1...bind4 would be available
      ...)))

...

要在没有宏的情况下执行此操作,您可以这样做:

(def m {:a 1 :b 2})

(deftest foo []
  (println (m :a)))

(foo)
;; prints 1

(let [m (assoc m :c 3)]
  (deftest bar
    (println (m :c))))

(bar)
;; prints 3

您可以使用固定装置重新定义跨测试的动态绑定并访问 deftest 中的值。夹具可以为所有或每个 deftest 定义一次。

(def ^:dynamic m)

(defn once-fixture
  [tests]
  (binding [m {:a 1 :b 2}]
    (tests)))

(use-fixtures :once once-fixture)

(deftest testing-binding
  (is (= (:a m) 1)
    "Dynamic binding is working"))