你已經離工作的功能版本不遠了。我改變了一些東西,使其更加習慣於Clojure。
以下假設產生天空節點,併產生熱節點都返回一定的價值(這可以在除任何副作用他們完成),即:
(defn generate-sky-nodes
[]
(doseq [i (range 10)] (do-make-sky-node i))
:sky-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))
(在上面的測試代碼比照測試將使用該版本的工作以及)
好問題。在我看來,你正試圖對聲明性代碼應用命令式的風格測試。你不應該描述*事情是如何工作的,而是他們做了什麼,所以被調用的函數是一個不相關的細節。不過功能編程專家會確認(我不知道)。 – guillaume31
@ guillaume31,我認爲這是模擬和存根之間的區別。存根只是爲了提供支持行爲的假實現,而嘲諷也是這樣做的,並且還會計帳。就我個人而言,我發現嘲笑是非常糟糕的主意,即使在面向對象的世界。在功能世界中是雙重的。但它可能只是我。 – ivant
@ivant Dunno。我猜測存根仍會以某種方式描述* how *,儘管如果沒有他們可能無法獲得高性能測試。嘲笑我個人覺得有用,不是爲了微觀會計,而是爲了驗證一個對象不會向其中的一個對等方說粗魯(即外部協議),這使得在OO類型系統中缺乏這些協議的流暢執行。 – guillaume31