2024 Clojure 状态调查! 中分享您的想法。

欢迎!请查看 关于页面 了解更多关于如何使用本站的信息。

0 投票
Spec

在尝试手动连接 clojure.test 和 spec 以供 fdef'ed 函数使用时,我意识到 spec.test/check 对失败的测试返回一个包含 (link: :failure false) 的映射。我(几乎)确信它应该返回 true,因为 spec.test/abbrev-result 用 spec.test/check 的返回值作为参数,并测试 :failure 的值。我无法产生一个 spec.test/check 对失败的测试返回 (link: :failure true) 的案例。仅为了信息,对于通过测试它返回一个不包含 :failure 键的映射。

以下是 REPL 中的一个简单的重现案例

(defn foo-fn (link: x) "bar")

(s/fdef foo-fn

    :args (s/cat :x any?)
    :ret string?)

(stest/check `foo-fn) ;; => 无错误,打印正常小的映射,无 :failure 条目

(defn foo-fn (link: x) 1)

(stest/check `foo-fn) ;; => 完整错误映射,:failure 等于 false。:failure 显示在下面

(-> (stest/check `foo-fn) first :failure) ;; => false

9 个回答

0 投票

评论由:gfredericks 提出

这并不是一个错误,尽管它确实令人困惑。

{{stest/check}} 将从 {{clojure.test.check/quickcheck}} 返回的值的(至少一部分)返回值传递,后者返回属性返回的值,这些值被评估为真假以确定通过还是失败。由于非真值只能是 {{false}} 或 {{nil}},查看它并没有学得很多(尽管也可能在 {{:failure}} 键下有异常,这将更加有信息量)。

test.check 的下一个版本应该有一种更实用、更不易混淆的方式来从测试中提取信息,但我不知道在使用 {{stest/check}} 时的具体样子会如何。

0 投票

评论人:djebbz

我还是不明白为什么你不把这个当作一个错误。`stest/check` 的文档字符串说 ":failure 可选测试失败"。我预期只有在测试失败时才会有 `:failure` 键(因此称为“可选”),并提供一些有用的信息。

我正在使用 `stest/abbrev-result` 来显示 `stest/check` 的输出,它期望 `:failure` 为真以便显示所有有用的失败信息。如果 `stest/check` 返回 `false`,则出现不匹配,我认为这是一个错误。《`stest/abbrev-result` 的文档字符串明确指出它接收检查结果的参数,所以我并没有将方枘楔入圆孔。

感谢你这么快就回答了我,并感谢你的时间。

0 投票
_评论人:grzm_

`:failure` 的 `false` 值确实令人困惑。《`stest/abbrev-result`》 在 `{{{:failure false}}}` 中的表现非常令人困惑,因为它没有提供失败通常提供的信息,正如 [~djebbz] 指出的那样。

{codehttps://github.com/clojure/spec.alpha/blob/2824ad49df8deadcb4b75acdf624e732a85b4ac7/src/main/clojure/clojure/spec/test/alpha.clj#L438-L446}
(defn abbrev-result
  "给定一个检查结果,返回一个适合摘要使用的缩略版本。"

  [x]
  (if (:failure x)
    (-> (dissoc x ::stc/ret)
            (update :spec s/describe)
            (update :failure unwrap-failure))
    (dissoc x :spec ::stc/ret)))


下面是一个示例,说明这可能有多误导性


(require '[clojure.spec.alpha :as s]
         '[clojure.spec.test.alpha :as stest])

(alias 'stc 'clojure.spec.test.check)

(defn adder [a b]
  (+ a b))

(s/fdef adder
        :args (s/cat :a int? :b int?)
        :ret string?)

(-> (stest/check `adder) first stest/abbrev-result)
;; => {:sym ex.check-test/adder, :failure false}

;; 编写 `abbrev-result` 的替代版本,检查 `true`


(defn- failure-type [x] (::s/failure (ex-data x)))
(defn- unwrap-failure [x] (if (failure-type x) (ex-data x) x))

(defn- abbrev-result [x]
  (let [failure (:failure x)]
    (if-not (or (true? failure)
                (nil? failure))
      (-> (dissoc x ::stc/ret)
          (update :spec s/describe)
          (update :failure unwrap-failure))
      (dissoc x :spec ::stc/ret))))

(-> (stest/check `adder) first abbrev-result)
;; => {:spec (fspec :args (cat :a int? :b int?) :ret string? :fn nil),
;;     :sym ex.check-test/adder,
;;     :failure false}


再次提醒,任何**真值**的{{:failure}}值都将提供额外的细节,而**假值**的{{:failure}}值则不会。

我理解不更改{{:failure}}键值的动机。如果该值要保留,我认为{{stest/abbrev-result}}也应该更新,以便显式地测试{{nil}}和{{true}},而不仅仅是真值,以保持与{{stest/check}}结果的一致性。

0 投票

评论人:djebbz

非常感谢Michael。最后我选择了一个小的改动,我并不使用(dissoc x ::stc/ret),而是保留整个检查结果,因为其中包含了堆栈跟踪、spec/explain-data映射、缩小的失败案例等。

0 投票

评论者:grzm

看起来{{abbrev-result}}应该使用{{result-type}}来测试检查是否通过。附带一个补丁,这可以做到这一点。如果您需要为它编写测试,我很乐意重新提交。

编辑:我太急了。我将进行调查并重新提交。很抱歉造成混乱。

编辑2:我第一次猜测是错误的。我非常肯定我是正确的。我认为补丁是好的。

0 投票

评论由:gfredericks 提出

请注意,在test.check的master分支上还有未发布的变化,这些变化可能会影响到在这里的最佳做法。(链接:[https://github.com/clojure/test.check/blob/master/src/main/clojure/clojure/test/check/results.cljc 文本:这些内容)尤其是。

0 投票
_评论人:grzm_

谢谢[~gfredericks]。结果协议是值得注意的事情。我认为在{{abbrev-result}}级别使用{{result-type}}是正确的抽象。我想,在{{make-check-result}}中装饰{{quick-check}}结果时,应该使用{{Result/passing?}}而不是[{{(true? result)}}|https://github.com/clojure/spec.alpha/blob/2824ad49df8deadcb4b75acdf624e732a85b4ac7/src/main/clojure/clojure/spec/test/alpha.clj#L319]调用]. 这对您来说有意义吗?
0 投票

评论由:gfredericks 提出

是的,我认为是这样的。但是我审查了规范代码,看到有多少关于返回值的细节是依赖的(这可能是其他test.check用户的情况,也不应该让我感到惊讶),我认为我会将Result协议的细节保存到{{quick-check-2}}。

0 投票
参考文献: https://clojure.atlassian.net/browse/CLJ-2246(由 alex+import 报告)
...