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

欢迎!请参阅关于页面来获取更多有关该运作方式的信息。

0投票
test.check

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

我更希望检查导致失败的特定输入的属性。朝这个方向的一步是给每个试验一个显式的不同种子(也许是从一个初始元种子生成的),在失败时报告一个可以使用以运行测试单次的[[种子大小]]对。

然而,这种机制如何与缩小机制相互作用是很有趣的,因为我也可能会想要在失败的缩小值上再次运行。由于缩小值从未明确地从已知的[[种子大小]]生成,只有这些信息是不够的。我们也许可以报告{{[种子大小缩小路径]}},其中第三个元素是一个索引列表,用于遍历缩小树。可能这个问题最糟糕的一面是它可能会相当长。

无论如何,我认为这种机制比当前的设置更有用。我可能会在自己维护的分支上实现类似的机制,但如果我们可以确定一个具体的设计,我将很高兴编写一个补丁。

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}} 和一个普通函数。但 #1 比较难以解决,而一个小的元组对我来说更加方便。

我已经编写了这个概念的初始版本,并且它运行得相当好。我使用了 {{:key}} 这个术语来指代元组,所以这个术语不会与 {{:seed}} 冲突。我运行测试的方式是 {{(foo 0 :key [329489249329323 19 []])}},但我可能会想出一些不需要传递一个虚假的第一个参数的方法。

0投票

评论者:gfredericks

我认为随着 TCHECK-96 的出现,这类问题变得更加重要,因为如果一个缩减提前中止,那就很希望能够再次运行它,而无需时间限制(而不必像重新运行 {{quick-check}} 一样重新运行所有之前通过测试)。

我刚刚想到了这个问题的中间方法,这个方法不会有我在分支中使用的任意长“key”的缺点:我们将 RNG 提升为真正的可序列化值,然后在 {{quick-check}} 中,我们跟踪每个试验中使用的 {{[rng size]}} 对,一旦失败,就报告这个对。然后,我们有一个类似于 {{quick-check}} 的新函数,该函数接受一个属性和一个对,并在一个试验中运行(失败时进行缩减)。

0投票
参考:[链接](https://clojure.atlassian.net/browse/TCHECK-21)(由 gfredericks 提出)
...