请将您的想法分享到2024 年 Clojure 状态调查!

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

0 投票
test.check

Test.check 在测试属性时使用一个种子。这个种子可以提供或由当前时间生成。无论如何,这个单一的种子用于生成所有测试的试验。如果测试失败,尝试重新测试相同输入属性的唯一方法是使用相同的种子再次运行所有测试。如果测试在发现失败之前已经运行了数小时,这将非常不利于。

我更愿意检查失败的恰好输入的属性。朝这个方向迈出的一步是每个试验都有明确的种子(也许由初始元种子生成),在失败时报告一个可以用于运行测试一次的 {{[seed size]}} 对。

然而,这种方式与收缩交互有趣,因为我可能会想要重新运行失败的收缩值。由于收缩值从未从已知的 {{[seed size]}} 明确生成,仅此信息是不够的。我们可能报告 {{[seed size shrink-path]}},其中第三个元素是一个索引列表,用于遍历收缩树。可能最糟糕的部分是这可能相当长。

无论如何,我认为这比当前设置更有用。我可能要在维护的分支上对面类似的东西进行篡改,但如果我们可以就具体设计达成一致,我将非常乐意编写补丁。

4 个答案

0 投票
_评论由 reiddraper 提出_

当测试失败时,我们确实返回最初失败的参数,以及收缩测试的参数。这是否不足够?

例如

{code:none}
      {:result false,
       :failing-size 45,
       :num-tests 46,
       :fail [[10 1 28 40 11 -33 42 -42 39 -13 13 -44 -36 11 27 -42 4 21 -39]],
       :shrunk {:total-nodes-visited 38,
                :depth 18,
                :result false,
                :smallest [[42]]}}


参见 {{:fail}} 和 {{[:shrunk :smallest]}}。
0 投票

评论者:gfredericks

在理论上这当然可以重现,但我不知道有任何内置机制能使其容易实现。以下是我最终采取的做法

给定以下

`
(defspec foo
(prop/for-all [x gen]

(f x)))

`

在得到一个包含50行缩减值(例如 {{:bar}})的失败后,我手动格式化它并将其粘贴回我的文件,如下所示

`
(def shrank
':bar)

(defspec foo
(prop/for-all [x #_gen (gen/return shrank)]

(f x)))

`

现在我可以运行 {{(foo 1)}} 以重新运行并使用失败的值。

这种尴尬是由于以下三个事实部分引起的

  1. 我的生成器创建了大型的难以操作的数据值
  2. 我的属性是一小块代码而不是一个单独的函数
  3. 没有简单的测试特定值属性的方法

通过更改2中的方法,即把每一个测试拆分为{{defspec}} / {{prop/for-all}}和普通函数,我可以在一定程度上减轻痛苦。但第一个问题不容易解决,对我而言,拥有一个小元组会更好。

我已经为这个功能编写了一个摘要证明(POC),并且它非常有效。我用{{:key}}来指代这个元组,因此这个术语不会与继承自{{:seed}}的术语冲突。最后,我把测试命名为{{(foo 0 :key [329489249329323 19 []])}}】,但我可能会想出一些不需要传递虚拟第一个参数的新名字。

0 投票

评论者:gfredericks

我认为随着TCHECK-96的出现,这类问题变得更加重要,因为如果缩减提前终止,那么能够在没有时间限制的情况下再次运行它将会很好(而不必像重新运行带有相同种子的{{quick-check}}一样重新运行所有先前通过测试)。

针对这个问题,我刚刚想到了一个想法,它不具有我在分叉中使用的不定长的“键”的缺点:我们将RNG提升为真正的序列化值,然后在{{quick-check}}中跟踪每次试验用于的{{[rng size]}}对,并在失败时报告该对。然后我们有一个类似于{{quick-check}}的新函数,它接受属性和一对进行测试,并在失败时执行缩减。

0 投票
参考:https://clojure.atlassian.net/browse/TCHECK-21(由gfredericks报告)
...