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

不能比较函数以检查它们是否相等,所以我认为您应该调查在测试中使用的此策略的替代方案。您可以测试函数的相同性,但这通常是一个非常脆弱的测试。

通过
有人告诉我这件事,但为什么 (= + +) 是真的呢?或者问题出在 tests 中的 'is' 上。而且...另一方面,我进行了这个测试并且一切正常。

(定义 get-encoder [encoder]
  (根据 encoder
    :icase encoder-icase
    :simple encoder-simple
    :advanced encoder-advanced
    encoder-icase))

(定义测试 get-encoder
  (当 (f/get-encoder :icase) 是一个函数?)
  (等式 (f/get-encoder nil) f/encoder-icase))
  (等式 (f/get-encoder :icase) f/encoder-icase))
  (等式 (f/get-encoder :simple) f/encoder-simple))
  (等式 (f/get-encoder :advanced) f/encoder-advanced)))

你说的测试函数是用来识别的,为什么它很脆弱?对不起,如果我的问题是愚蠢的,这是我的第一语言。你能推荐一些这方面的阅读材料吗?

感谢你的时间,alexmiller!
通过
在 `(= + +)` 中,你看到了一个标识符检查(相同的函数对象正在被比较)。在这一点上,函数很奇怪,因为它们只在标识符上相等,但是有很多方法可以看到两个执行相同操作但不是相同的函数。这只是一般情况下我不会在测试中信任的事情。
通过
好的,但还是我不理解为什么它对 (= (f/get-encoder nil) f/encoder-icase) 是成立的,而对应的是 (= #(string/split % (or split #"\W+")) f/init/fn--14976) 这两个是相同的函数
对匿名函数 #(string/split % (或 split #"\W+")) 的每次调用都返回一个新的(在身份上)不同的函数,尽管在功能上它确实做了相同的事情。

此外,f/init/fn--14976 就是 REPL 打印的函数。在这个例子中,由于它是一个匿名函数,它没有绑定到符号,即使看起来像有绑定。在 f/encoder-icase 的情况下,函数绑定到符号 f/encoder-icase。这也是为什么它“工作”的原因。正如 alexmiller 所说,测试函数身份充其量是脆弱的。一般来说,测试相等性是不可判定的。
概念变得更加清晰...感谢 Dorab 和 Alex!
...