Was Sie haben, ist schon nicht weit von einer Arbeitsfunktionsfähige Version. Ich habe die Dinge etwas verändert, um Clojure idiomatischer zu sein.
Im Folgenden wird angenommen, dass die Erzeugung-Himmel-Knoten und erzeugen Hot-Knoten jeweils einen Wert zurückgeben (dies kann zusätzlich zu irgendwelchen Nebenwirkungen durchgeführt werden sie haben), dh:
(defn generate-sky-nodes
[]
(doseq [i (range 10)] (do-make-sky-node i))
:sky-nodes)
dann, Ihre generieren-Knoten wird wie folgt angepasst:
(defn generate-nodes
[sky-blue? hot-outside? name]
(cond
(sky-blue? name) (generate-sky-nodes)
(hot-outside?) (generate-hot-nodes)))
und schließlich die funktionsfähige Version der Tests:
(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)))))
Die allgemeine Idee ist, dass Sie nicht testen, was es getan hat, Sie testen, was es zurückgibt. Dann ordnen Sie Ihren Code so an, dass (wann immer möglich) alles, was für einen Funktionsaufruf wichtig ist, zurückgegeben wird.
Ein weiterer Vorschlag ist, die Zahl der Plätze zu minimieren, wo Nebenwirkungen passieren durch generate-sky-nodes
und generate-hot-nodes
mit der Nebenwirkung zurückzukehren durchgeführt werden:
(defn generate-sky-nodes
[]
(fn []
(doseq [i (range 10)] (do-make-sky-node i))
:sky-nodes))
und Ihren Anruf von generate-nodes
würde wie folgt aussehen :
(apply (generate-nodes blue-test hot-test name) [])
oder kurz und bündig (obwohl zugegebenermaßen merkwürdig, wenn Sie weniger vertraut mit Clojure sind):
((generate-nodes blue-test hot-test name))
(mutatis mutandis im obigen Test Code die Tests auch mit dieser Version arbeiten)
Gute Frage. Es scheint mir, dass Sie versuchen, imperativen Stiltest auf deklarativen Code anzuwenden.Du sollst nicht beschreiben * wie * Dinge funktionieren, aber * was * sie tun, also ist eine aufgerufene Funktion IMO ein irrelevantes Detail. Allerdings von funktionalen Programmierern bestätigt zu werden (was ich nicht bin). – guillaume31
@ guillaume31, ich denke das ist der Unterschied zwischen Mocks und Stubs. Stubs sind nur dazu da, gefälschte Implementierungen von unterstützendem Verhalten zu liefern, während Mocks das tun und auch Buchhaltung leisten. Persönlich finde ich Mocks als außergewöhnlich schlechte Idee, sogar in der OO-Welt. Doppelt so in der funktionalen Welt. Aber es kann nur ich sein. – ivant
@ivant Dunno. Ich denke, Stubs beschreiben irgendwie immer noch das * wie *, obwohl Sie wahrscheinlich nicht ohne sie auskommen können, um performante Tests zu erhalten. Sprüche, die ich persönlich finde, sind nützlich, um Mikro-Accounting nicht durchzuführen, sondern um zu verifizieren, dass ein Objekt nicht unhöflich (d. H. Externes Protokoll) zu einem seiner Peers spricht, was das Fehlen einer reibungslosen Durchsetzung dieser Protokolle in OO-Typsystemen bewirkt. – guillaume31