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

欢迎!有关如何使用本站的信息,请查阅关于页面。

0
test.check
我在阅读 John Hughes 的 "QuickCheck 测试:乐趣与收益" 论文中的示例时,希望我在这些测试中生成的结构看起来像这样
 
 [:apply `reg [(gen-name) (gen/elements pids)]]

而不是现在必须这样表示

 (gen/tuple (gen/return :apply) (gen/return `reg) (gen/tuple (gen-name) (gen/elements pids)))

我认为可以使用一个简单的递归函数来生成这些,前提是当前生成器创建一个地图 {:gen #<fn...>},我建议改为记录,以便我们可以区分生成器和地图数据结构。

这看起来在 Quvig QuickCheck 中已经得到了很好的实现

bq. 在一般情况下,Quviq QuickCheck 允许任何包含嵌入式生成器的数据结构作为该形状数据结构的生成器使用,这对于用户来说非常方便,但在 Haskell 中则不可能,因为在数据结构中嵌入生成器通常会引发类型错误。这种技术被用在 Ericsson 编写的所有生成器中。 -- Hughes

9 个答案

0

评论者:pangloss

今天我在 REPL 中玩耍,想到了这个代码,可以将任意文字转换为生成器,看起来效果不错

`
(defprotocol LiteralGenerator
(-literal->generator [literal]))

(defn literal->generator [literal]
(cond

(satisfies? LiteralGenerator literal) (-literal->generator literal)
(vector? literal) (apply gen/tuple (mapv literal->generator literal))
(and (map? literal) (= [:gen] (keys literal)) (fn? (:gen literal))) literal
(map? literal) (gen/fmap (partial into {}) (literal->generator (mapv vec literal)))
(set? literal) (gen/fmap set (literal->generator (vec literal)))
(list? literal) (gen/fmap (partial apply list) (literal->generator (vec literal)))
:else (gen/return literal)))

`

处理记录可能是通常很有用的,所以我添加了这一点

`
(defn record->generator
([record]
; 有没有更好的方法来做这件事?
(let [ctor (eval (read-string (str "map->" (last (clojure.string/split (str (class record)) #"\.")))))]

 (record->generator ctor record)))

([ctor record]
(gen/fmap ctor (literal->generator (into {} record)))))
`

这使我能够扩展一个记录,例如这样

(defrecord Foo [a b] LiteralGenerator (-literal->generator [this] (record->generator map->AbcDef this)))

我还没有深入研究将这段代码整合到test.check中。在我继续推进之前,我想得到一些关于到目前为止取得成果的反馈。

0

评论由:reiddraper

所以,我对这件事有些矛盾的感觉。我同意这很方便,但我也担心这种宽松的方式可能导致更多的意外发生,并且不会强制用户区分值和生成器。例如,如果你输入的是这样的:{{[int int]}}。你是想输入{{[gen/int gen/int]}},还是你真正旨在编写{{[(gen/return int) (gen/return int)]}}呢?如果每个期望生成器的函数也能接受值,我们就不能再开始添加错误检查来确保你正确地传递生成器。在这一点上,我也看到使用数据结构字面量的好处。如果我们编写一个必须使用这种语法创建生成器的函数,那么会怎样:{{(gen/literal [:age gen/int])}}。这样你就可以选择性地使用这种语法,但仅限于gen/literal的作用域内?

0

评论者:pangloss

我同意这是一个担忧,由于你不能确保看到生成器的输出,因此最好明确使用gen/literal。这还是一个干净的解决方案。幸运的是,这正是我写的!我们只需要将literal->generator重命名为{{literal}},并安装到clojure.test.check.generators命名空间。

0

评论由:reiddraper

我认为第一步是改变生成器以使用记录。你对为此制作补丁感兴趣吗?

0
_评论由:pangloss_

一个非常简单的补丁,使用生成器记录而不是简单的:gen ƒ)映射。
0
_由 reiddraper_ 订阅的评论:

我在ef132b5f85a07879f01417c9104aa6dea771fdb4中应用了record-patch。谢谢。我还添加了一个{{generator?}}辅助函数。
0

由 ppotter 订阅的评论:

我发现了一些看似相关的内容:ztellman/collection-check定义了一个类似于fn gen/tuple的=text: tuple,它会自动用gen/return包住字面量。

值得注意的是,尽管这没有解决一般情况,但它已经解决了问题描述中的示例。

0

由 gfredericks 订阅的评论:

现在有一个针对此目的的库:https://github.com/holguinj/jen

0
参考:https://clojure.atlassian.net/browse/TCHECK-19 (由 pangloss 报告)
...