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)并不能工作

我猜想这可能是一个与vars相关的技巧,但我不知道它到底是如何工作的。如果您能提供任何阅读材料,我将不胜感激。

---编辑--- 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)))

你说的测试函数为什么是身份测试,为什么是脆弱的?如果我的问题很傻,是我的第一语言。你能推荐一些关于这方面的阅读材料吗?

感谢你的时间,alex!
In `(= + +)` 你看到的是一个身份检查(比较的是相同函数对象)。函数在这方面很奇怪,因为只有身份相等,但有许多方法可以看到两个执行相同操作但不是相同的函数。这通常不是我在测试中会信任的东西。
虽然是这样,但我还是不明白为什么(= (f/get-encoder nil) f/encoder-icase)可以工作,而像 (= #(string/split % (or split #"\W+")) f/init/fn--14976) 这样的完全相同的函数就不能工作。
对匿名函数 #(string/split % (or split #"\W+")) 的每次调用都会返回一个新的不同(从身份角度来说)的函数,即使从功能上讲,它做的是同样的操作。

此外,f/init/fn--14976 正是 REPL 打印出的函数名称。  在这种情况下,由于它是一个匿名函数,它未绑定到任何符号,尽管看起来好像是的。  对于 f/encoder-icase 的情况,函数绑定到符号 f/encoder-icase。  这就是为什么它“工作”的原因。  如 alexmiller 所述,检查函数身份在最佳情况下也很脆弱。  通常情况下,检查相等性是不可判定的。
by
概念变得更加清晰...感谢 Dorab 和 Alex!
...