clojure.test.check生成两个整数,比另一个整数少一个

时间:2015-11-18 22:07:47

标签: clojure quickcheck property-based-testing

我想写一个如下属性:

(prop/for-all [x (gen/nat)
               y (gen/nat)]
  (= (g x y) (f x y)))

但是,该属性仅在x > y时保留。表达此属性的前提条件的正确方法是什么? (更好的是,我如何编写此属性,使y生成为小于x的自然数?)

2 个答案:

答案 0 :(得分:5)

  1. 您可以生成y和中间数字dy,然后将x计算为(+ y dy)

    使用dy生成clojure.test.check.generators/nat可确保它是非负的 - 无需在用户代码中应用绝对值。如果x需要严格大于 - 而不等于 - y,请使用clojure.test.check.generators/pos-int生成dy

    我认为,为了产生最小的失败案例,我们倾向于将两个数字更接近的情况视为“更简单”。对于许多场景来说,这似乎是一个有用的属性 - 你必须判断它是否适合你。

  2. 您可以独立生成xy并使用拒绝抽样 - clojure.test.check.generators/such-that允许您使用您选择的谓词“过滤”基础生成器生成的值

    当你正在寻找的情况以非常低的概率生成时,这不是一个很好的方法,但在所有情况下,x将大于y,所以它应该没问题。

  3. 您可以按照迈克的建议使用clojure.test.check.generators/bind。我建议与clojure.test.check.generators/choose一起使用它来生成一个正x,然后在[0 ... x-1]范围内生成一个y,可能采用以下方式:

    (prop/for-all [[x y] (gen/bind gen/nat
                           (fn [v]
                             (gen/tuple
                               (gen/return (inc v))
                               (gen/choose 0 v))))]
      (> x y))
    

答案 1 :(得分:3)

您可以使用bind函数创建依赖于先前值的生成器。我确定必须有更清洁的方法来做到这一点。

(def always-greater-than
  (gen/bind gen/nat
           (fn [v] (gen/tuple (gen/return (inc v))
                              (gen/fmap #(mod % (inc v)) gen/nat)))))

示例输出:

(gen/sample always-greater-than)
([1 0] [2 0] [1 0] [3 0] [1 0] [6 4] [7 6] [2 0] [3 2] [6 4])