【发布时间】:2016-10-01 22:05:37
【问题描述】:
考虑来自新 lein new app arrow-mve 的 MVE(最小可行示例)命名空间中的以下函数。函数extract-one 是公共的,函数extract-two 是私有的。我包含 main- 函数只是为了完整性和它在我的问题中涉及的远程可能性:
(ns arrow-mve.core
(:gen-class))
(defn extract-one [m]
(-> m :a))
(defn- extract-two [m]
(-> m :a))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
在我的并行测试命名空间中,我可以按如下方式测试这些函数。我可以通过直接调用或使用箭头线程宏-> 来测试公共函数extract-one。另请注意,在直接调用中通过完整的Var 引用私有函数extract-two 没有问题。这些测试通过了:
(ns arrow-mve.core-test
(:require [clojure.test :refer :all]
[arrow-mve.core :refer :all]))
(deftest test-one-a
(is (= 1 (extract-one {:a 1, :b 2}))))
(deftest test-one-b
(is (= 1 (-> {:a 1, :b 2}
extract-one))))
(deftest test-two-a
(is (= 1 (#'arrow-mve.core/extract-two
{:a 1, :b 2}))))
但是当我尝试使用箭头宏调用私有函数extract-two 时出现编译错误:
(deftest test-two-b
(is (= 1 (-> {:a 1, :b 2}
#'arrow-mve.core/extract-two))))
$ lein test
Exception in thread "main" java.lang.RuntimeException: Unable to resolve var: arrow.mve.core/extract-two in this context, compiling: (arrow_mve/core_test.clj:10:12) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyze(Compiler.java:6625)
当我让测试变得更复杂时,事情变得更奇怪了。
(deftest test-two-b
(is (= {:x 3.14, :y 2.72}
(-> {:a {:x 3.14, :y 2.72}, :b 2}
#'arrow-mve.core/extract-two))))
$ lein test
Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Symbol, compiling:(arrow_mve/core_test.clj:18:10) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875) at clojure.lang.Compiler.analyze(Compiler.java:6669) at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856)
同样,测试以直接调用形式通过:
(deftest test-two-b
(is (= {:x 3.14, :y 2.72}
(#'arrow-mve.core/extract-two
{:a {:x 3.14, :y 2.72}, :b 2}))))
我怀疑问题是通过deftest、is、Var 的阅读器宏#' 和箭头宏进行宏链接的限制,我想知道这是设计使然还是潜在的漏洞。当然,在我的实际应用程序(不是这个 MVE)中,我有长而深的调用链,这使得使用箭头宏非常可取。
【问题讨论】:
标签: clojure macros clojure-testing