Clojure 使用deftest测试集合项

Clojure 使用deftest测试集合项,clojure,Clojure,我正在尝试使用clojure.test和deftest宏编写一些测试 (deftest a-test (for [item collection] (is (= (f item) :a-value)))) 但是我意识到这不是执行这个测试的正确方法。我搜索了文档并找到了“are”宏,但我不确定在这种情况下如何使用它 编写这样的测试的首选方法是什么?您的测试不起作用的原因是for只是构建了一个惰性序列;它不像在其他编程语言中那样是一个命令式循环。有几种方法可以重写此测试 (deftes

我正在尝试使用clojure.test和deftest宏编写一些测试

(deftest a-test
  (for [item collection]
    (is (= (f item) :a-value))))
但是我意识到这不是执行这个测试的正确方法。我搜索了文档并找到了“are”宏,但我不确定在这种情况下如何使用它


编写这样的测试的首选方法是什么?

您的测试不起作用的原因是
for
只是构建了一个惰性序列;它不像在其他编程语言中那样是一个命令式循环。有几种方法可以重写此测试

(deftest a-test
  (are [item] (= (f item) :a-value)
    :a
    :b
    :c
    ;; other collection items here...
  ))
使用
every?
函数测试集合中的所有项是否满足谓词。这可能是最少的代码量,但缺点是,如果测试失败,您将不知道哪个特定项失败

(deftest a-test
  (is (every? #(= (f %) :a-value) collection)))
使用
are
重写测试如果要测试的集合中的项目是特定于此测试的输入的硬编码列表,则这是一个很好的选择,而且更加惯用

(deftest a-test
  (are [item] (= (f item) :a-value)
    :a
    :b
    :c
    ;; other collection items here...
  ))
最后,您可以使用
doseq
换成
。对于编写测试来说,这稍微不那么惯用,但它的优点是,它可以处理以编程方式生成的测试输入集合

(deftest a-test
  (doseq [item collection]
    (is (= (f item) :a-value))))

如果不知道您试图解决的问题的更多细节,就很难说您应该使用什么,但我可以根据实际的潜在问题给出一些可能有用的可能性

如果(正如我所怀疑的)你对
for
的懒惰有问题,一个简单的改变是将
for
改为
doseq
,以确保懒惰不会伤害你(可能已经可以了)

比如说,

(deftest b-test (for [item (range 100)] (test/is (< item 80))))
将有一系列失败(对于大于或等于80的每个项目)。请注意,唯一的区别是
->
doseq

are
是关于提供通过给定谓词的不同输入和输出,因此假设
:a-value
可以在
f
的不同应用程序中变化,这可能很有用:

(deftest a-test
  (are [x y] (= x y)
     (f item-1) :value-1
     (f item-2) :value-2
     (f item-3) :value-3))
另一方面,如果应用
f
时,
集合
的每个成员应具有相同的结果,则更简洁地说:

(deftest a-test
  (is (every? (fn [item] (= (f item) :a-value))
              collection)))

谢谢,我确实是以编程方式生成集合的。