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

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

我听说了那个,但为什么(= + +)成立呢?或者问题出在测试的'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)))

你对于测试函数的认同是什么意思,为什么它很脆弱?如果你的问题听起来很傻,因为这是我的第一语言。你能推荐一些关于这方面的读物吗?

感谢你抽出时间,亚历克斯!
在`(= + +)`中,你看到的是一个身份检查(比较的是相同函数对象)。在这一点上,函数很奇怪,因为它们只在身份上相等,但你可能会看到很多方式,两个功能做同样的事情但不是相同的。这通常不是我在测试中会相信的事情。
好的,但仍然不明白为什么在(= (f/get-encoder nil) f/encoder-icase)下能成立,而在(= #(string/split % (or split #"\W+")) f/init/fn--14976)下不成立,如果它们是完全相同的函数呢。
by
匿名函数 #(string/split % (or split #"\W+")) 的每次调用都返回一个新的不同(就身份而言)的函数,尽管在功能上它做的是同一件事。

f/init/fn--14976 正是 REPL 输出的函数名。在这种情况下,由于它是一个匿名函数,它没有绑定到一个符号上,即使它看起来像是绑定了一样。在 f/encoder-icase 的情况下,函数绑定到符号 f/encoder-icase 上。这也就是为什么它“有效”。正如 alexmiller 所说的,测试函数身份在最坏的情况下也是脆弱的。一般来说,测试相等性是不可判定的。
by
这个概念变得清晰了...谢谢 Dorab 和 Alex!
...