【问题标题】:Using a generative test library in clojure vs build your own using higher order functions在 clojure 中使用生成测试库与使用高阶函数构建自己的测试库
【发布时间】:2014-10-08 18:42:23
【问题描述】:

Clojure 有许多用于生成测试的库,例如 test.checktest.generativedata.generators

可以使用高阶函数来创建可组合的随机数据生成器,例如:

(defn gen [create-fn content-fn lazy]
  (fn [] (reduce #(create-fn %1 %2) (for [a lazy] (content-fn)))))

(def a (gen str #(rand-nth [\a \b \c]) (range 10)))
(a)

(def b (gen vector #(rand-int 10) (range 2)))
(b)

(def c (gen hash-set b (range (rand-int 10))))
(c)

这只是一个示例,可以使用不同的参数、过滤器、部分等进行修改,以创建非常灵活的数据生成函数。

任何生成库都可以做的事情是不是也可以通过组合一些高阶函数来简洁地实现(或更多)?

作为对 stackoverflow 诸神的附注:我不认为这个问题是主观的。我不是在征求关于哪个图书馆更好的意见。我想知道任何/所有数据生成库的特定功能或技术将它们与组合普通高阶函数区分开来。一个示例答案应该说明使用任何库生成随机数据,并解释为什么按照我上面说明的方式编写 HOF 会更复杂。

【问题讨论】:

    标签: clojure generative-testing


    【解决方案1】:

    test.check 这样做方式 更好。最值得注意的是,假设您生成了一个包含 100 个元素的随机列表,并且您的测试失败:您处理该列表的方式是错误的。现在怎么办?你如何找到基本的错误?它肯定不完全取决于那 100 个输入。您可能可以使用仅包含几个元素的列表来重现它,如果您的基本案例有问题,甚至可以使用一个空列表。

    使所有这些真正有用的功能不是随机生成器,而是这些生成器的“缩小”。一旦 test.check 找到破坏测试的输入,它会尝试尽可能简化输入,同时仍然使测试破坏。对于整数列表,收缩很简单,您可以自己做:删除任何元素,或减少任何元素。即使这样也可能不是真的:选择收缩的顺序可能是一个比我意识到的更难的问题。对于较大的输入,例如从向量到 [string, int, keyword] 的 3 元组的映射列表,您会发现它完全无法管理,而 test.check 已经完成了所有艰苦的工作。

    【讨论】:

    • 收缩算法是否真的依赖于数据生成器?我可以看到它可能会如何,但它也可能是有用的(尽管可能不实用/容易),因为它是独立的。例如,如果我有一个在常规数据上失败的不变断言(即未测试),那么能够沿着堆栈跟踪将输入缩小回来可能非常方便..
    • 它确实取决于生成器。涉及很多管道,但基本上一个生成器包括用于产生输出和缩小输出的功能。您不能真正对具有生成模型的任意数据运行收缩器。
    • 这几乎是 test.check 和 test.generation 之间的区别。 Test.generation 基本上是@optevo 的实现,但经过了打磨。正因为如此,它更容易扩展和定制。虽然 test.check 很棒,但由于它的容量正在缩小,因此为它编写自己的生成器更加困难。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多