在clojure中使用生成测试库,使用更高阶函数构建自己的库

时间:2014-10-08 18:42:24

标签: clojure generative-testing

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来做更复杂的事情。

1 个答案:

答案 0 :(得分:5)

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

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