请在 2024年Clojure调查问卷 中分享您的想法!

欢迎!请访问关于 页面以获取更多关于如何使用本站的信息。

0 投票
测试

当我想测试一个结果为另一个函数的函数时会发生这种情况。我有一个类似这样的例子

  ns flexsearch.core

    (defn init [{:keys [tokenizer split indexer filter] :as options}]
  (let [encoder (get-encoder (:encoder options))]
    (assoc (merge {:ids {} :data {}} options)
           :indexer (get-indexer indexer)
           :encoder encoder
           :tokenizer (if (fn? tokenizer) tokenizer #(string/split % (or split #"\W+")))
           :filter (set (mapv encoder filter)))))

在测试命名空间中

ns flexsearch.core-test
[flexsearch.core :as f]

(def split #"\W+")

(is (= (f/init {:tokenizer false :split split :indexer :forward :filter #{"and" "or"}})
         {:ids {},
          :data {},
          :tokenizer f/init/fn--14976,
          :split #"\W+",
          :indexer f/index-forward,
          :filter #{"or" "and"},
          :encoder f/encoder-icase}))

在repl中的结果是

{:ids {},
 :data {},
 :tokenizer #function[flexsearch.core/init/fn--14976],
 :split #"\W+",
 :indexer #function[flexsearch.core/index-forward],
 :filter #{"or" "and"},
 :encoder #function[flexsearch.core/encoder-icase]}

我知道我必须使用f/index-forward代替repl中的结果[flexsearch.core/index-forward],但这与f/init/fn--14976(未找到变量:f/init/fn--14976)不兼容

我猜想这可能是一个关于变量的技巧,但我不确定它实际上是如何工作的。如果您能提供一些读书材料,我将不胜感激。

---编辑--- f/index-forward和f/encoder-icase的表示法可以正常工作。

---编辑2--- 我已经定义了

(defn spliter [split]   (fn [x] (string/split x (or split #"\W+"))))
and used it on:

(defn init [{:keys [tokenizer split indexer filter] :as options}]
  (let [encoder (get-encoder (:encoder options))]
    (assoc (merge {:ids {} :data {}} options)
           :indexer (get-indexer indexer)
           :encoder encoder
           :tokenizer (if (fn? tokenizer) tokenizer (spliter split))
           :filter (set (mapv encoder filter)))))

我得到了一个类似的":tokenizer #function[flexsearch.core/spliter/fn--34857]",",我在测试中使用了它,它也失败了——

1 答案

+2 投票

你不能比较函数来检查相等性,所以我认为你应该调查测试中该策略的替代方案。你可以测试函数的身份,但这通常是一个非常脆弱的测试。

我听说过了,但为什么例如(= + +)是真实的?或者是test中的‘is’出了问题。另一方面,我进行了这个测试,它运行正常。

(defn get-encoder [encoder]
  (case encoder
    :icase encoder-icase
    :simple encoder-simple
    :advanced encoder-advanced
    encoder-icase))

(deftest get-encoder
  (is (fn? (f/get-encoder :icase)))
  (is (= (f/get-encoder nil) f/encoder-icase))
  (is (= (f/get-encoder :icase) f/encoder-icase))
  (is (= (f/get-encoder :simple) f/encoder-simple))
  (is (= (f/get-encoder :advanced) f/encoder-advanced)))

你是什么意思要对身份和测试函数进行测试,为什么它又脆弱?如果我的问题很愚蠢,对不起,这是我的第一语言。你能推荐一些关于这个的阅读材料吗?

感谢你的时间,alexmiller!
在`(= + +)`中,你看到的是一个身份检查(完全相同的函数对象正在比较)。函数在这方面很奇怪,因为它们只有在使用同一对象时才相等,但有很多方法你可以看到两个做同样事情但不是同一对象的函数。这通常不是我会在测试中信任的。
好,但是我仍然不明白为什么会运行(= (f/get-encoder nil) f/encoder-icase)而不运行(= #(string/split % (or split #"\W+")) f/init/fn--14976),如果它们也是完全相同的函数的话
by
每次对匿名函数 #(string/split % (或 split #"\W+")) 的调用都会返回一个全新的、在身份上不同的函数,尽管在功能上它做的是同一件事情。

此外,f/init/fn--14976 就是 REPL 输出的函数名称。在这种情况下,由于它是一个匿名函数,它并未绑定到一个符号,即使看起来是这样。在 f/encoder-icase 的情况下,函数绑定到了符号 f/encoder-icase。这就是为什么它能够“工作”。正如 alexmiller 所提到的,测试函数身份至多是一种脆弱的方法。通常来说,测试等价性是不可判定的。
by
这个概念变得更清晰了...感谢 Dorab 和 Alex!
...