我尝试使用clojure.test和deftest宏编写一些测试。
(deftest a-test
(for [item collection]
(is (= (f item) :a-value))))
但我已经意识到这不是执行此测试的正确方法。我搜索了文档,发现'是'宏,但我不确定如何在这些情况下使用它。
编写此类测试的首选方法是什么?
答案 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
的懒惰中遇到麻烦,一个简单的改变,以确保懒惰不会咬你(可能已经好了)将是改变for
至doseq
。
例如,
(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)))