你已经拥有的离一个可用的功能版本不远了。我改变了一些东西,使其更符合 Clojure 的习惯。
以下假设 generate-sky-nodes 和 generate-hot-nodes 每个都返回一些值(除了它们具有的任何副作用之外,还可以这样做),即:
(defn generate-sky-nodes
[]
(doseq [i (range 10)] (do-make-sky-node i))
:sky-nodes)
然后,您的 generate-nodes 调整如下:
(defn generate-nodes
[sky-blue? hot-outside? name]
(cond
(sky-blue? name) (generate-sky-nodes)
(hot-outside?) (generate-hot-nodes)))
最后,测试的功能版本:
(deftest when-sky-blue-then-generate-sky-nodes
(let [truthy (constantly true)
falsey (constantly false)
name nil]
(is (= (generate-nodes truthy falsey name)
:sky-nodes))
(is (= (generate-nodes truthy truthy name)
:sky-nodes))
(is (not (= (generate-nodes falsey falsey name)
:sky-nodes)))
(is (not (= (generate-nodes falsey truthy name)
:sky-nodes)))))
一般的想法是你不测试它做了什么,你测试它返回什么。然后你安排你的代码,以便(尽可能地)关于函数调用的所有事情都是它返回的内容。
generate-sky-nodes
另一个建议是通过使用和generate-hot-nodes
返回要执行的副作用来最小化发生副作用的地方的数量:
(defn generate-sky-nodes
[]
(fn []
(doseq [i (range 10)] (do-make-sky-node i))
:sky-nodes))
并且您的电话generate-nodes
如下所示:
(apply (generate-nodes blue-test hot-test name) [])
或者更简洁(尽管如果你对 Clojure 不太熟悉的话,这很奇怪):
((generate-nodes blue-test hot-test name))
(在上述测试代码中进行必要的修改后,测试也将适用于该版本)