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`,那么这是一个我认为的bug。`stest/abbrev-result` 的文档字符串明确说明它接受检查的结果作为参数,因此我没有在方孔中塞进圆木。

感谢你这么快就回复我,感谢你的时间。

0
_评论者:grzm_

`:failure` 的 `false` 值确实令人困惑。当 `stest/abbrev-result` 作为 `{{{:failure false}}}` 时的混淆也非常令人费解,因为它没有提供如 [~djebbz] 所指出的失败通常提供的信息。

{code:title=https://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` 键的值的动机。如果将保持该值,我认为 `stest/abbrev-result` 应当相应更新,明确测试 `null` 和 `true`,而不是真值,以保持与 `stest/check` 结果的一致性。

0

评论者:djebbz

非常感谢Michael。最后我选择了一个小的变体,不执行(dissoc x ::stc/ret),而是保留整个检查结果,因为它包括堆栈跟踪、spec/explain-data映射、缩小的失败用例等。

0

评论人:grzm

看起来{{abbrev-result}}应该使用{{result-type}}来测试检查是否通过。附上一个实现此功能的补丁。如果您需要相应的测试,我很乐意重新提交。

编辑:太仓促了。将进行调查并重新提交。抱歉造成噪音。

编辑2:怀疑自己第一次思考是错误的。我非常确信我第一次是正确的。我认为补丁是好的。

0

评论者:gfredericks

注意,test.check的主分支上的未发布更改可能会影响此处最佳做法。特别是。(链接: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

是的,我认为这样。但现在我审查了spec代码并看到许多关于返回值的偶然细节被依赖(这可能适用于其他test.check用户,而且不应该让我惊讶),我认为我将为{{quick-check-2}}保留结果协议的细节(链接:TCHECK-142 文本:https://dev.clojure.org/jira/browse/TCHECK-142)。

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