使用 deftest 测试集合项

Testing collection items using deftest

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

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

但我意识到这不是执行此测试的正确方法。我搜索了文档并找到了 'are' 宏,但我不确定在这些情况下如何使用它。

编写此类测试的首选方法是什么?

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

使用 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...
  ))

最后,您可以 for 替换为 doseq。这对于编写测试来说不太习惯,但它的优点是它可以处理以编程方式生成的测试输入集合。

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

如果不了解您要解决的问题的更多细节,很难说您应该使用什么,但我可以给您一些 可能 有用的可能性,具体取决于关于实际的潜在问题是什么。

如果(正如我所怀疑的那样)您在 for 的懒惰方面遇到麻烦,一个简单的更改可以确保懒惰不会咬住您(可能已经没问题了)将更改 fordoseq.

例如,

(deftest b-test (for [item (range 100)] (test/is (< item 80))))

会由于for生成的序列的惰性而通过,这不是循环而是列表理解。这可能不是我想要的。但是

(deftest c-test (doseq [item (range 100)] (test/is (< item 80))))

会有一堆失败(每一项大于或等于 80)。请注意,唯一的区别是 for -> 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))

另一方面,如果 collection 的每个成员在应用 f 时都应该有相同的结果,那么这样说会更简洁:

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