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

欢迎!请参阅 关于 页面以了解更多关于此的功能信息。

0
test.check

Haskell QuickCheck 允许 for-all 表达式嵌套。当生成值之间有依赖关系时,这很有用。test.check 也应该允许这样做。

目前,嵌套的 for-all 总是成功,这在某种程度上是有害的。

我已经添加了一个实现这一功能的补丁。

9 个回答

0

评论者:reiddraper

感谢 Michael。我很欣赏您的补丁,但在进入代码级别的细节之前,我们可以讨论一些设计细节。作为一个独立但相关的问题,我一直想实现类似于您的 {{CheckResult}} 类型,但它是一个包含更多字段的记录。这些字段将持有任何找到的错误的无格式描述、统计信息(类似于 QuickCheck 的 {{collect}}、{{classify}} 等)。我还想编写一个协议,它允许基本类型(如布尔型)被转换为这种记录。这类似于 Haskell QuickCheck 的 {{Testable}} 类型类。虽然这是一个独立的问题,但我认为我们应该与可嵌套的 for-all 一起解决它,尤其是在嵌套 for-all 可以仅通过在生成器级别使用绑定来模拟的情况下。这是否合理?

0

评论者:sperber

当然。

我个人会从这个补丁开始,除非您想进行根本性的改变。

无论如何,我能如何帮助使它变成现实呢?

0

评论者:reiddraper

好问题。让我想想这个,尽快给你答复。我也很希望尽快实现这个性能。

0
评论人:reiddraper_

抱歉延误,这是我一直在用的草图


diff --git a/src/main/clojure/clojure/test/check/properties.clj b/src/main/clojure/clojure/test/check/properties.clj
index 99b5222..139ae9a 100644
--- a/src/main/clojure/clojure/test/check/properties.clj
+++ b/src/main/clojure/clojure/test/check/properties.clj
@@ -8,13 +8,47 @@
 ;   必须保留此声明,或任何其他声明,不得从该软件中删除。
 
 (ns clojure.test.check.properties
+  (:import clojure.test.check.generators.Generator)
   (:require [clojure.test.check.generators :as gen]))
 
+(defrecord Result [result pass? message stamps])
+
+(defprotocol ToResult
+  (to-result [a]))
+
+(extend java.lang.Object
+  ToResult
+  {:to-result (fn [b]
+                看起来这里不应检查捕获的异常
+                (->Result b (not (false? b)) nil nil))})
+
+(extend nil
+  ToResult
+  {:to-result (fn [b]
+                (->Result b false nil nil))})
+
+(extend java.lang.Boolean
+  ToResult
+  {:to-result (fn [b]
+                (->Result b b nil nil))})
+
+(extend Generator
+  ToResult
+  {:to-result identity})
+
+(extend Result
+  ToResult
+  {:to-result identity})
+
+(defn message
+  [m property]
+  (assoc property :message m))
+
 (defn- apply-gen
   [function]
   (fn [args]
-    (let [result (try (apply function args) (catch Throwable t t))]
-      {:result result
+    (let [result (to-result (try (apply function args) (catch Throwable t t)))]
+      {:result (:result result)
        :function function
        :args args})))
 
@@ -29,9 +63,18 @@
   (for-all* [gen/int gen/int] (fn [a b] (>= (+ a b) a)))
   "
   [args function]
-  (gen/fmap
-    (apply-gen function)
-    (apply gen/tuple args)))
+  (gen/bind
+    (apply gen/tuple args)
+    (fn [a]
+      (let [result ((apply-gen function) a)]
+        (cond (gen/generator? result) (gen/fmap (fn [r] (println "foo") (update-in r :args #(conj % a))) result)
+               NOTE: quick note to myself before I leave this code for the night,
+               this :else is getting hit because we're wrapping the result
+               with a {:result ...} map. Should probably do that conditionally.
+               We also need two result types I think, a result to return from
+               a property itself, and a reuslt that tacks the 'args' on top of this.
+               :else (do (println "bar") (gen/return result)))))
+    ))
 
 (defn binding-vars
   [bindings]
0

评论者:sperber

看起来没问题。然而,很难理解为什么这会比我的补丁更快地将您带到您想要去的地方...

0

评论者:reiddraper

bq. 看起来没问题。然而,很难理解为什么这会比我的补丁更快地将您带到您想要去的地方...

公平。在这部分中,更简单的是,我编写草稿 easier for me to write up a sketch。当支持嵌套生成器时,我试图涵盖的主要问题是确保

  1. 我们也支持即将到来的收集和返回测试统计信息的能力,类似于 Haskell QuickCheck 中的 {{collect}}
  2. 我们有一个合理的机制将失败的测试返回给用户。目前,在返回映射的 {{:fail}} 和 {{:smallest}} 关键字中,我们告诉用户失败的参数。由于您可能使用了一个以上的生成器 {{prop/for-all}},因此它们始终至少被一个向量包装。对于嵌套属性怎么办呢?我们如何区分“同一级别”上的多个生成器与嵌套属性?或者我们不需要区分?我们决定的任何行动是否可以向后兼容?

重点是,我想确保我们不承诺嵌套属性直到我们得到一些这些问题的答案,而且对我个人来说,尝试一起尝试这些事情并看看它们是如何适合更简单

0
_评论由:expez_ 发表

我真的不想层叠 for-all,我更希望它能像 let 一样工作,我们可以引用前面的值。其次,无论哪种解决方案,这都是我对 test.check 现在最严重的抱怨,所以任何解决方案都优于另一年的吊床时间。

这是一个解决方案,从野外采集而来。我确信还有许多其他解决方案,人们都非常需要,但这一个是从 Nathan Marz 的 specter library 中采集而来的


(defmacro for-all+ [bindings & body]
  (let [parts (partition 2 bindings)
        vars (vec (map first parts))
        genned (reduce
                  (fn [curr [v code]]
                   `(gen/bind ~code (fn [~v] ~curr)))
                  `(gen/return ~vars)
                (reverse parts))]
    `(prop/for-all [~vars ~genned]
                   ~@body )))
0

评论者:gfredericks

我们一直在思考一个类似问题(链接:[TCHECK-81](http://dev.clojure.org/jira/browse/TCHECK-81) 文本:TCHECK-81),与此同时,还存在一个更漂亮的{{for-all}}变体(链接:[here](https://github.com/gfredericks/test.chuck#properties) 文本:这里)。

0
参考:[https://clojure.atlassian.net/browse/TCHECK-44](https://clojure.atlassian.net/browse/TCHECK-44)(alexf+import 报告)
...