2024Clojure状态调查中分享你的想法!

欢迎!请访问关于页面获取更多关于这个网站如何工作的小信息。

+1投票
多方法

以下的行为让我感到惊讶:
1. 定义一个调用 (is (= 的测试
2. 覆盖 clojure.test/assert-expr 多方法来定义针对 = 的自定义测试,使其在只有一个项目存在时出错
3. 运行测试时,由于它不会出错,所以多方法没有被调用
4. 重新定义测试
5. 此时,新的多方法被调用。

我确信存在一个小的重现案例,但这是真实世界用法中出现的情况。CIDER通过其中间件更改了这种报告,但中间件仅在实际需要后动态加载。因此,这种行为仅在您使用CIDER的测试功能并 重新定义您的测试 后才会发生。

我想知道这是否按预期行为执行,因为 de f test 把测试放在元数据里,还是这是一个实际的错误。

(require '[clojure.test :refer [deftest is assert-expr]])
(deftest foo (is (= (println 1))))

(foo) ;; no error

(defn =-body
  [msg expected more]
  (if (seq more)
    `(let [more# (list ~@more)
           expected# ~expected
           result# (apply = expected# more#)]
       (->> (if result#
              {:type :pass}
              {:type :fail
               :diffs (->> (remove #(= expected# %) more#)
                           (map #(vector % (data/diff expected# %))))})
            (merge {:message ~msg
                    :expected expected#
                    :actual more#})
            test/do-report)
       result#)
    `(throw (Exception. "= expects more than one argument"))))

(defmethod assert-expr '= [msg [_ expected & more]]
  (=-body msg expected more))

(foo) ;; no error
(deftest foo (is (= (println 1))))
(foo) ;; error

1 答案

+1投票

由于 is 是一个宏,它在编译时使用 assert-expr 多方法展开代码,因此运行 deftest 后更改 assert-expr 不会更改该测试函数的行为,因为它已经展开和编译。

这就是为什么您看不到新的 assert-expr 功能,直到您定义新的测试(或重新定义现有的测试)。

...