test.check:'properties/for-all' 中的 let 风格行为

test.check: let-style behaviour in 'properties/for-all'

继那里提到的这个 , and the blog post 之后,prop/for-all 不直接加入这种能力是有原因的吗?例如。类似于:

(require '[clojure.test.check.generators :as gen])
(require '[clojure.test.check.properties :as prop])
(require '[clojure.test.check.clojure-test :refer :all])

(defspec some-props-test
  (prop/for-all [n (gen/choose 1 10)
                 v (gen/vector gen/int n) ;; treat n like its produced value
                 e (gen/element v)]
    ... do stuff with n, v & e ...
  ))

基本上,我想在另一个生成器中重新使用一个生成器生成的,然后引用生成器中生成的两个值实际测试代码。这实际上会将 for-all 的 sugar/magic 扩展为允许在宏提供的类似 let 的块中引用生成的值,因为它在下面的表达式块中工作。

如果我遗漏了使这成为可能的其他东西,或者由于某种原因实施它没有意义,请告诉我。

我在该系列中找到了后来的博客 post,它完全清除了 test.check 的用法(需要先阅读一些 monads 才能理解)。所以首先可以声明 monad:

(require '[clojure.algo.monads :as m])

(m/defmonad gen-m
    [m-bind gen/bind
     m-result gen/return])

(def vector-and-elem
  (m/domonad gen-m
    [n (gen/choose 1 10)
     v (gen/vector gen/int n)
     e (gen/element v)]
    [n v e]))

gen-m monad 允许引用将为先前声明的生成器生成的值。

然后,可以直接在for-all调用中使用:

(defspec some-props-test
  (prop/for-all [[n v e] vector-and-elem]
    ... do stuff with n, v & e ...
  ))

您可以通过向量(或映射,如果您愿意)和 [=30] 将与 constraint-checking 代码相关的所有值传递到 gen-m monad 调用生成的表达式中=] 它得到你需要的东西。

不过,如果这在 for-all 中自动完成就好了,但这已经足够好了。

我同意此功能可能比 for-all 当前的功能更有用。它没有被更改的主要原因是 backwards-compatibility(虽然使用旧样式的代码不会中断,但它不会像以前那样收缩)。

但是您有更多的选择,而不仅仅是 monad:

  • gen/let,它使用 let 样式的绑定(它不是 for-all 的 drop-in 替代品,但您可以将它们一起使用)
  • com.gfredericks.test.chuck.generators/fortest.chuck 帮助程序库中定义——它就像是 gen/let
  • 的高级版本
  • com.gfredericks.test.chuck.properties/for-all,在同一个库中,drop-in替代for-all