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

您提到的关于测试函数身份和为什么它是脆弱的?如果我的问题很愚蠢,我会为我的第一语言感到抱歉。您能推荐一些有关这方面的阅读材料吗?

感谢您的宝贵时间,亚历克斯!
在 `(= + +)` 中,您可以看到一个身份检查(相同函数对象进行比较)。在这方面,函数很奇怪,因为它们只在身份上相等,但有很多方式您可以看到两个执行相同操作但不是同一对象的函数。这通常不是一个我会信任的测试。
嗯,但仍然我不懂为什么它能用 (= (f/get-encoder nil) f/encoder-icase) 来工作,但不能用 (= #(string/split % (or split #"\W+")) f/init/fn--14976),因为它们也是完全相同的函数。
即使匿名函数 #(string/split % (or split #"\W+")) 在功能上做了相同的事情,每次调用都会返回一个全新的不同(就身份而言)函数。

...