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 可以通过在生成器级别使用 bind 来模拟,这有道理吗?

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]
+               )))) not checking for caught exceptions here
+               (->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 (执行 (println "bar") (gen/return result)))))
+ ))
 
 (defn 绑定变量
   [绑定]
0

评论者:sperber

看起来可以。然而,很难理解这怎么会比我的修复更快地达到你想要去的地方...

0

评论者:reiddraper

bq. 看起来可以。然而,很难理解这怎么会比我的修复更快地达到你想要去的地方...

当然。其中的一个原因是我写草图比较容易。我在支持嵌套生成器时试图覆盖的主要事项是确保

  1. 我们还支持即将到来的收集和返回测试统计数据的能力,就像 Haskell QuickCheck 的 {{collect}}
  2. 我们有合理的方法将失败的测试返回给用户。现在,在返回映射的 {{:fail}} 和 {{:smallest}} 键中,我们告诉用户失败的参数。由于您可能使用多个生成器,所以它们总是至少被一个向量包装。那么我们如何处理嵌套的属性呢?我们如何在 '同一级别' 的多个生成器之间与其他嵌套属性区分开来?或者我们不需要区分?我们做的任何事情都能向后兼容吗?

重点是,我想确保在我们有一些答案之前,我们不承诺嵌套属性,对我来说,尝试将这些事物一起尝试并查看它们如何融合在一起更容易。

0
_评论由 expez 提出

我真的不希望必须嵌套 for-all,我更愿意它像 let 那样工作,这样我们就可以引用先前值。话虽如此,不管哪种解决方案,这目前都是我最关心的问题,测试.check 所以任何解决方案都比再花一年棒。

这是一个解决方案,来自野外。我敢肯定还有其他很多,人们迫切需要这个,但这个是从 Nathan Marz 的 specter 库中摘取的。


(defmacro for-all+ [绑定 & body]
  (let [parts (partition 2 绑定)
      变量 (vec (map first parts))
      生成 (reduce
                  (fn [当前 [v 代码]]
                   `(gen/bind ~代码 (fn [~v] ~当前)))
                `(gen/return ~变量)
               `(reverse parts))]
    `(prop/for-all [~变量 ~生成]
                   ~@body )))
0

评论者:gfredericks

我们一直在考虑(链接:http://dev.clojure.org/jira/browse/TCHECK-81 文本:TCHECK-81),在此期间还有一个更加华丽的 {{for-all}} 变体(链接:https://github.com/gfredericks/test.chuck#properties 文本:在这里)。

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