cljs.core/test
的工作方式与它的文档字符串描述不符。
cljs.core/test
的定义是:
(defn test
"test [v] finds fn at key :test in var metadata and calls it,
presuming failure will throw exception"
[v]
(let [f (.-cljs$lang$test v)]
(if f
(do (f) :ok)
:no-test)))
据我理解,它的预期用途如下(下面例子是从 ClojureDocs 的 https://docs.clojure.org/clojure.core/test#example-542692cac026201cdc326b8a 同名函数文档中复制的):
(defn my-function
"this function adds two numbers"
{:test #(do
(assert (= (my-function 2 3) 5))
(assert (= (my-function 4 4) 8)))}
([x y] (+ x y)))
(test #'my-function) ;equal to (test (var my-function))
=> :ok
因此,cljs.core/test
允许函数通过在 :test
键下提供的测试来自我说明其功能。
然而,在 CLJS 环境中重复上述操作会得到不同的结果。
(defn my-function
"this function adds two numbers"
{:test #(do
(assert (= (my-function 2 3) 5))
(assert (= (my-function 4 4) 8)))}
([x y] (+ x y)))
(test #'my-function)
=> :no-test
有趣的是,鉴于我在 CLJS REPL 中评估了上述代码,据我所知,元数据确实是可用的。
(meta #'my-function)
=>
{:ns cljs.user,
:name my-function,
:file "<cljs repl>",
:end-column 18,
:source "my-function",
:column 1,
:line 1,
:end-line 1,
:arglists ([x y]),
:doc "this function adds two numbers",
:test #object[Function]}
通过将相对隐晦的函数替换为一个关键字,这可以更加清楚。
(defn my-function
"this function adds two numbers"
{:test :just-a-keyword}
([x y] (+ x y)))
(meta #'my-function)
=>
{:ns cljs.user,
:name my-function,
:file "<cljs repl>",
:end-column 18,
:source "my-function",
:column 1,
:line 1,
:end-line 1,
:arglists ([x y]),
:doc "this function adds two numbers",
:test :just-a-keyword}
我在 Clojurians Slack 上与 @theller 和 @hiredman 讨论了这个问题,他们认为 cljs.core/test
可能已经被重新用于执行 deftest
的主体,因为这两者似乎可以搭配使用。观察一下:
(require '[cljs.test :as test])
(test/deftest foo (test/is (= 1 2)))
=> #'cljs.user/foo
(test foo)
FAIL in () (<NO_SOURCE_FILE>:1:28)
expected: (= 1 2)
actual: (not (= 1 2))
:ok
deftest
的主体被执行,并返回了关键字 :ok
(无论 is
的结果如何),这也可以从阅读 cljs.core/test
的定义中得出。
如果真的是这样的话,那么还有两个真实的情况:
A) 如果原本的意图是让 cljs.core/test
启用对 defn
的 :test
断言进行测试,那么这不再成立。
B) cljs.core/test
的文档字符串有点误导。
文档字符串的开头部分,"test [v] finds fn at key :test in var metadata and calls it"
可能是技术上正确的,但没有提到与 deftest
的关联,因此不是很有用。
文档字符串的第二部分,", presuming failure will throw exception"
,在用于 deftest
时显然是不正确的——我猜想大多数 deftest
都使用了 cljs.test/is
宏,它会捕获异常并代替报告。我认为原始的意图是抛出异常,这样就不会返回 :ok
,但在这种上下文中,这个结构失败了。
文档字符串似乎是 Clojure 版本的复制品,所以可能需要更新。或者,cljs.core/test
可能在这个阶段既未使用又过时了?