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 发表的评论:

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


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)
+              ;;; 注意:在离开这门代码之前,快速提醒自己,
+              这个:else 是因为我们在将结果
+              用 {:result ...} 映射来包装的。
+              ;; 我想我们还需要两种结果类型,一种
+              用于从属性本身返回,另一种则将 'args'
+              放在这个结果之上。
+              :else (do (println "bar") (gen/return result)))))
 
 
 (defn binding-vars [bindings]
0 投票

评论由 sperber 提出

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

0 投票

评论由 reiddraper 提出

引用内容:看起来没问题。然而,很难理解为什么它会让你比我的补丁更快地达到你想要去的地方...

没问题。这部分是因为我写草图更容易。在支持嵌套生成器时,我主要尝试涉及的要点是确保

  1. 我们还支持即将到来的收集和返回测试统计信息的能力,类似于 Haskell QuickCheck 中的 {{collect}}
  2. 我们有合理的方法将失败的测试返回给用户。目前,在返回的映射的 {{:fail}} 和 {{:smallest}} 键中,我们告诉用户失败的参数。由于你可能会使用一个以上的生成器通过 {{prop/for-all}},它们总是至少被一个向量封装。我们如何处理嵌套属性?我们如何区分“同一级别”的多个生成器与嵌套属性?或者我们不需要区分?我们所决定的东西能否与旧版本向后兼容?

关键是,我想确保我们不是在没有获得一些答案之前就致力于嵌套属性,对我来说,尝试一起尝试这些事情更容易,看看它们将如何结合在一起。

0 投票
_由:expez_

我实在不想嵌套使用 for-all,我更希望它能像 let 一样工作,我们可以参考之前的值。话虽如此,无论哪种解决方案,这目前都是我对 test.check 最不满的地方,因此任何解决方案都会比再浪费一年时间好。

这有一个解决方案,来自野外。我相信还有很多其他的方案,人们急需这个,但这是从 Nathan Marz 的 specter 库中取出的


(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

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

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