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

你能解释一下测试函数的标识和为什么它脆弱?如果我的问题很傻,请原谅,这是我的第一语言。你能推荐一些有关这方面的阅读材料吗?

感谢你的时间,alexei!
在 `(= + +)` 中,你看到的是一种标识检查(比较相同的函数对象)。在这个方面,函数很奇怪,因为它们仅在标识上相等,但你可能会看到很多做相同事情但不相同标识的函数。这通常不是我在测试中会相信的事情。
好吧,但仍然我不明白为什么它适用于 (= (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!
...