使用deftest测试集合项

时间:2015-01-05 14:00:31

标签: clojure

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

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

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

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

2 个答案:

答案 0 :(得分:6)

你的测试不起作用的原因是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))))

答案 1 :(得分:1)

如果不了解您尝试解决的问题的更多细节,很难说您应该使用什么,但我可以为您提供可能有用的一些可能性,取决于实际的潜在问题。

如果(因为我怀疑)你在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 - &gt; 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)))